summaryrefslogtreecommitdiff
path: root/gcc/c-family
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-05-02 14:43:35 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-05-02 14:43:35 +0000
commit34efdaf078b01a7387007c4e6bde6db86384c4b7 (patch)
treed503eaf41d085669d1481bb46ec038bc866fece6 /gcc/c-family
parentf733cf303bcdc952c92b81dd62199a40a1f555ec (diff)
downloadgcc-tarball-34efdaf078b01a7387007c4e6bde6db86384c4b7.tar.gz
gcc-7.1.0gcc-7.1.0
Diffstat (limited to 'gcc/c-family')
-rw-r--r--gcc/c-family/ChangeLog1512
-rw-r--r--gcc/c-family/array-notation-common.c30
-rw-r--r--gcc/c-family/c-ada-spec.c355
-rw-r--r--gcc/c-family/c-ada-spec.h2
-rw-r--r--gcc/c-family/c-attribs.c3175
-rw-r--r--gcc/c-family/c-cilkplus.c52
-rw-r--r--gcc/c-family/c-common.c5951
-rw-r--r--gcc/c-family/c-common.def2
-rw-r--r--gcc/c-family/c-common.h240
-rw-r--r--gcc/c-family/c-cppbuiltin.c301
-rw-r--r--gcc/c-family/c-dump.c2
-rw-r--r--gcc/c-family/c-format.c2446
-rw-r--r--gcc/c-family/c-format.h2
-rw-r--r--gcc/c-family/c-gimplify.c6
-rw-r--r--gcc/c-family/c-indentation.c6
-rw-r--r--gcc/c-family/c-indentation.h2
-rw-r--r--gcc/c-family/c-lex.c102
-rw-r--r--gcc/c-family/c-objc.h2
-rw-r--r--gcc/c-family/c-omp.c27
-rw-r--r--gcc/c-family/c-opts.c96
-rw-r--r--gcc/c-family/c-pch.c2
-rw-r--r--gcc/c-family/c-ppoutput.c3
-rw-r--r--gcc/c-family/c-pragma.c8
-rw-r--r--gcc/c-family/c-pragma.h4
-rw-r--r--gcc/c-family/c-pretty-print.c57
-rw-r--r--gcc/c-family/c-pretty-print.h2
-rw-r--r--gcc/c-family/c-semantics.c2
-rw-r--r--gcc/c-family/c-target-def.h2
-rw-r--r--gcc/c-family/c-target.def2
-rw-r--r--gcc/c-family/c-target.h2
-rw-r--r--gcc/c-family/c-ubsan.c73
-rw-r--r--gcc/c-family/c-ubsan.h4
-rw-r--r--gcc/c-family/c-warn.c2286
-rw-r--r--gcc/c-family/c.opt213
-rw-r--r--gcc/c-family/cilk.c41
-rw-r--r--gcc/c-family/cppspec.c2
-rw-r--r--gcc/c-family/stub-objc.c2
37 files changed, 10400 insertions, 6616 deletions
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index 328cfa9ac4..b4a3295833 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,19 +1,1256 @@
-2016-08-22 Release Manager
+2017-05-02 Release Manager
- * GCC 6.2.0 released.
+ * GCC 7.1.0 released.
+
+2017-04-27 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/80534
+ * c-common.c (complete_array_type): Only hash TYPE_TYPELESS_STORAGE
+ flag on non-aggregate element types.
+
+2017-04-20 Jakub Jelinek <jakub@redhat.com>
+
+ PR middle-end/80423
+ * c-common.c (complete_array_type): Preserve TYPE_TYPELESS_STORAGE.
+
+2017-04-18 Jakub Jelinek <jakub@redhat.com>
+
+ PR middle-end/79788
+ PR middle-end/80375
+ * c-common.c (c_common_type_for_mode): Don't handle
+ widest_*_literal_type_node here.
+ c_common_signed_or_unsigned_type): Likewise.
+ (c_common_nodes_and_builtins): Set widest_*_literal_type_node
+ to *intTI_type_node or *intDI_type_node depending on whether
+ TImode is supported by the target or not.
+
+2017-04-10 Martin Liska <mliska@suse.cz>
+
+ PR sanitizer/80350
+ * c-ubsan.c (ubsan_instrument_shift): Evaluate RHS before
+ doing an UBSAN check.
+
+2017-04-03 Jonathan Wakely <jwakely@redhat.com>
+
+ * c-warn.c (do_warn_double_promotion): Fix typo in comment.
+
+2017-03-31 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/79572
+ * c-ubsan.h (ubsan_maybe_instrument_reference): Change argument to
+ tree *.
+ * c-ubsan.c (ubsan_maybe_instrument_reference): Likewise. Handle
+ not just NOP_EXPR to REFERENCE_TYPE, but also INTEGER_CST with
+ REFERENCE_TYPE.
+
+2017-03-31 David Malcolm <dmalcolm@redhat.com>
+
+ PR documentation/78732
+ * c.opt (Wendif-labels): Fix description to refer to
+ #else rather than #elif.
+
+2017-03-31 Jakub Jelinek <jakub@redhat.com>
+
+ PR libstdc++/80251
+ * c-common.h (enum rid): Add RID_IS_AGGREGATE.
+ * c-common.c (c_common_reswords): Add __is_aggregate trait.
+
+2017-03-27 Jakub Jelinek <jakub@redhat.com>
+
+ PR middle-end/80162
+ * c-common.c (c_common_mark_addressable_vec): Don't set
+ TREE_ADDRESSABLE on DECL_HARD_REGISTER.
+
+2017-03-21 Martin Sebor <msebor@redhat.com>
+
+ PR c++/79548
+ * c-common.c (set_underlying_type): Mark type used only when
+ original del is declared unused.
+
+2017-03-10 David Malcolm <dmalcolm@redhat.com>
+
+ PR translation/79848
+ * c-format.c (check_format_string): Simplify uses of "%<%s%>" to
+ "%qs".
+
+2017-03-10 David Malcolm <dmalcolm@redhat.com>
+
+ PR c/79921
+ * c-indentation.c (warn_for_misleading_indentation): Remove parens
+ from inform's message, so that xgettext can locate it.
+
+2017-03-09 Marek Polacek <polacek@redhat.com>
+
+ PR c++/79962
+ PR c++/79984
+ * c-attribs.c (handle_nonnull_attribute): Save the result of default
+ conversion to the attribute list.
+
+2017-03-09 Martin Liska <mliska@suse.cz>
+
+ * c-ada-spec.c (macro_length): Increment value instead of a pointer.
+
+2017-03-03 Jason Merrill <jason@redhat.com>
+
+ * c.opt (Wnoexcept-type): New.
+
+2017-03-02 Richard Biener <rguenther@suse.de>
+
+ PR c/79756
+ * c-common.c (c_common_mark_addressable_vec): Look through
+ C_MAYBE_CONST_EXPR.
+
+2017-02-28 Martin Liska <mliska@suse.cz>
+
+ * c.opt: Replace space with tabular for options of <number>
+ type.
+
+2017-02-28 Martin Liska <mliska@suse.cz>
+
+ * c.opt: Fix --help=option -Q for options which are of
+ an enum type.
+
+2017-02-24 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/79588
+ * c-common.c (check_function_restrict): New function.
+ (check_function_arguments): Add FNDECL argument. Call
+ check_function_restrict if -Wrestrict.
+ * c-warn.c (warn_for_restrict): Remove ARGS argument, add ARGARRAY
+ and NARGS. Use auto_vec for ARG_POSITIONS, simplify.
+ * c-common.h (check_function_arguments): Add FNDECL argument.
+ (warn_for_restrict): Remove ARGS argument, add ARGARRAY and NARGS.
+
+2017-02-24 Eric Botcazou <ebotcazou@adacore.com>
+
+ * c-ada-spec.c (dump_ada_function_declaration): Add comment about the
+ treatment of parameters with pointer-to-tagged type and tidy up.
+ (print_ada_methods): Remove the special treatment of C++ static member
+ functions.
+
+2017-02-22 Martin Liska <mliska@suse.cz>
+
+ * c.opt: Replace inequality signs with square brackets
+ for -Wnornalized.
+
+2017-02-21 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/79641
+ * c-attribs.c (handle_mode_attribute): Use build_qualified_type to
+ preserve quals.
+
+2017-02-17 Joseph Myers <joseph@codesourcery.com>
+
+ * c-cppbuiltin.c (builtin_define_float_constants): Define
+ __DECIMAL_DIG__ to the value for long double.
+
+2017-02-15 Marek Polacek <polacek@redhat.com>
+
+ PR c/79515
+ * c-warn.c (do_warn_double_promotion): Don't warn if an invalid
+ conversion has occured.
+
+2017-01-24 David Malcolm <dmalcolm@redhat.com>
+
+ * c-common.c (c_common_reswords): Add "__RTL".
+ * c-common.h (enum rid): Add RID_RTL.
+
+2017-01-20 Marek Polacek <polacek@redhat.com>
+
+ PR c/64279
+ * c-common.h (do_warn_duplicated_branches_r): Declare.
+ * c-gimplify.c (c_genericize): Walk the function tree calling
+ do_warn_duplicated_branches_r.
+ * c-warn.c (expr_from_macro_expansion_r): New.
+ (do_warn_duplicated_branches): New.
+ (do_warn_duplicated_branches_r): New.
+ * c.opt (Wduplicated-branches): New option.
+
+2017-01-17 David Malcolm <dmalcolm@redhat.com>
+
+ PR c++/71497
+ * c-indentation.c (warn_for_misleading_indentation): Use the past
+ subjunctive in the note.
+
+2017-01-17 Aldy Hernandez <aldyh@redhat.com>
+
+ PR c/79116
+ * array-notation-common.c (cilkplus_extract_an_triplets): Convert
+ start type to integer_type.
+
+2017-01-16 Jakub Jelinek <jakub@redhat.com>
+
+ PR driver/49726
+ * c.opt (gen-decls): Add Driver flag.
+
+2017-01-16 Paolo Carlini <paolo.carlini@oracle.com>
+
+ Revert:
+ 2017-01-16 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/71737
+ * c-common.c (set_underlying_type): Always set DECL_ORIGINAL_TYPE.
+
+2017-01-16 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/71737
+ * c-common.c (set_underlying_type): Always set DECL_ORIGINAL_TYPE.
+
+2017-01-12 Martin Sebor <msebor@redhat.com>
+
+ (-Wformat-overflow): ...to this.
+
+2017-01-11 Martin Sebor <msebor@redhat.com>
+
+ PR c/78768
+ * c.opt (-Walloca-larger-than, -Wformat-length, -Wformat-truncation):
+ Also enable for LTO.
+
+2017-01-10 Jason Merrill <jason@redhat.com>
+
+ Implement P0195R2, C++17 variadic using.
+ * c-cppbuiltin.c (c_cpp_builtins): Define __cpp_variadic_using.
+
+2017-01-09 Jakub Jelinek <jakub@redhat.com>
+
+ PR translation/79019
+ PR translation/79020
+ * c.opt (Wnormalized=): Fix typo in description.
+
+2017-01-08 Martin Sebor <msebor@redhat.com>
+
+ PR middle-end/77708
+ * c.opt (-Wformat-truncation): New option.
+
+2017-01-06 Alexandre Oliva <aoliva@redhat.com>
+
+ * c-pretty-print.c (pp_c_tree_decl_identifier): Convert 16-bit
+ value to unsigned short to fit in 4 hex digits without
+ warnings.
+
+2017-01-05 Eric Botcazou <ebotcazou@adacore.com>
+
+ * c.opt (fsso-struct): Add 'native' value.
+
+2017-01-05 Martin Liska <mliska@suse.cz>
+
+ PR pch/78970
+ * c-opts.c (c_common_post_options): Reject '-' filename for a precompiled
+ header.
+
+2017-01-04 Marek Polacek <polacek@redhat.com>
+
+ PR c++/64767
+ * c.opt (Wpointer-compare): New option.
+
+2017-01-04 Jakub Jelinek <jakub@redhat.com>
+
+ PR driver/78957
+ * c.opt (fsso-struct=): Add RejectNegative.
+
+2017-01-01 Jakub Jelinek <jakub@redhat.com>
+
+ Update copyright years.
+
+2016-12-29 Martin Liska <mliska@suse.cz>
+
+ PR c/78933
+ * c.opt (strong-eval-order): Add RejectNegative keyword.
+
+2016-12-22 Jason Merrill <jason@redhat.com>
+
+ Implement P0522R0, matching of template template arguments.
+ * c-cppbuiltin.c (c_cpp_builtins): Define
+ __cpp_template_template_args.
+
+2016-12-21 Jakub Jelinek <jakub@redhat.com>
+
+ PR bootstrap/78817
+ * c-common.c (struct nonnull_arg_ctx): New type.
+ (check_function_nonnull): Return bool instead of void. Use
+ nonnull_arg_ctx as context rather than just location_t.
+ (check_nonnull_arg): Adjust for the new context type, set
+ warned_p to true if a warning has been diagnosed.
+ (check_function_arguments): Return bool instead of void.
+ * c-common.h (check_function_arguments): Adjust prototype.
+
+2016-12-21 Jason Merrill <jason@redhat.com>
+
+ * c.opt (-fnew-ttp-matching): New flag.
+ * c-opts.c (c_common_post_options): Default on if -std=c++1z.
+
+2016-12-14 Martin Jambor <mjambor@suse.cz>
+
+ * c-omp.c: Include omp-general.h instead of omp-low.h.
+ (c_finish_oacc_wait): Adjusted call to find_omp_clause to use its new
+ name.
+
+2016-12-14 Martin Sebor <msebor@redhat.com>
+
+ PR c/17308
+ * c-common.c (check_nonnull_arg): Disable when optimization
+ is enabled.
+
+2016-12-12 Marek Polacek <polacek@redhat.com>
+
+ PR c++/78647
+ * c-common.c (attribute_fallthrough_p): Return false for
+ error_mark_node.
+
+2016-12-08 Martin Sebor <msebor@redhat.com>
+
+ PR c/78284
+ * c.opt (-Walloc-zero, -Walloc-size-larger-than): New options.
+
+2016-12-08 Martin Sebor <msebor@redhat.com>
+
+ PR c/78165
+ * c-pretty-print (pp_c_integer_constant): Avoid formatting type
+ suffix.
+
+2016-12-07 Martin Sebor <msebor@redhat.com>
+
+ PR c/53562
+ PR middle-end/77784
+ PR middle-end/78149
+ PR middle-end/78138
+ * c.opt (-Wstringop-overflow): New option.
+
+2016-12-02 Maxim Ostapenko <m.ostapenko@samsung.com>
+
+ * c-attribs.c (asan odr indicator): New attribute.
+ (handle_asan_odr_indicator_attribute): New function.
+
+2016-11-26 Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org>
+
+ * c-common.c (c_common_nodes_and_builtins): Remove initialization of
+ ptrdiff_type_node;
+
+2016-11-23 James Greenhalgh <james.greenhalgh@arm.com>
+
+ * c-common.c (excess_precision_mode_join): New.
+ (c_ts18661_flt_eval_method): New.
+ (c_c11_flt_eval_method): Likewise.
+ (c_flt_eval_method): Likewise.
+ * c-common.h (excess_precision_mode_join): New.
+ (c_flt_eval_method): Likewise.
+ * c-cppbuiltin.c (c_cpp_flt_eval_method_iec_559): New.
+ (cpp_iec_559_value): Call it.
+ (c_cpp_builtins): Modify logic for __LIBGCC_*_EXCESS_PRECISION__,
+ call c_flt_eval_method to set __FLT_EVAL_METHOD__ and
+ __FLT_EVAL_METHOD_TS_18661_3__.
+
+2016-11-23 James Greenhalgh <james.greenhalgh@arm.com>
+
+ * c-opts.c (c_common_post_options): Add logic to handle the default
+ case for -fpermitted-flt-eval-methods.
+
+2016-11-23 Paolo Bonzini <bonzini@gnu.org>
+
+ * c.opt (Wexpansion-to-defined): New.
+
+2016-11-23 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/78451
+ * c-pragma.c (handle_pragma_target): Don't replace
+ current_target_pragma, but chainon the new args to the current one.
+
+2016-11-22 Nathan Sidwell <nathan@acm.org>
+
+ * array-notation-common.c (cilkplus_extract_an_trplets): Fix
+ indentation and formatting.
+
+2016-11-21 Martin Sebor <msebor@redhat.com>
+
+ * c.opt (-fprintf-return-value): Enable by default.
+
+2016-11-21 Bernd Edlinger <bernd.edlinger@hotmail.de>
+
+ PR c++/71973
+ * c.opt (-Wbuiltin-declaration-mismatch): New warning.
+ * c-common.c (c_common_nodes_and_builtins): Initialize
+ const_tm_ptr_type_node.
+
+2016-11-16 Marek Polacek <polacek@redhat.com>
+
+ PR c/78285
+ * c-common.c (c_add_case_label): Turn error_at calls into inform.
+
+2016-11-14 Jakub Jelinek <jakub@redhat.com>
+
+ * c-cppbuiltin.c (c_cpp_builtins): Define __cpp_structured_bindings.
+
+2016-11-14 Prasad Ghangal <prasad.ghangal@gmail.com>
+ Richard Biener <rguenther@suse.de>
+
+ * c-common.h (c_common_resword): Add RID_GIMPLE, RID_PHI types.
+ * c-common.h (enum rid): Add RID_GIMPLE, RID_PHI.
+ * c.opt (fgimple): New option.
+
+2016-11-13 Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org>
+
+ PR c/35503
+ * c-common.h (warn_for_restrict): Declare.
+ * c-warn.c: Include gcc-rich-location.h.
+ (warn_for_restrict): New function.
+ * c-format.c (gcc_tdiag_char_table): Add entry for "Z" specifier.
+ (gcc_cdiag_char_table): Likewise.
+ (gcc_cxxdiag_char_table): Likewise.
+ * c.opt (Wrestrict): New option.
+
+2016-11-13 Eric Botcazou <ebotcazou@adacore.com>
+
+ * c-ada-spec.c (print_ada_declaration): For typedef declarations, look
+ for nested types only if the type is a record or union and dump SLOC.
+
+2016-11-09 Jason Merrill <jason@redhat.com>
+
+ * c-cppbuiltin.c (c_cpp_builtins): Define __cpp_template_auto.
+
+2016-11-09 Jakub Jelinek <jakub@redhat.com>
+
+ * c-ubsan.c (ubsan_instrument_shift): Handle split
+ -fsanitize=shift-base and -fsanitize=shift-exponent.
+
+2016-11-07 Jason Merrill <jason@redhat.com>
+
+ * c.opt (Wc++1z-compat): New.
+ * c-cppbuiltin.c (c_cpp_builtins): Add __cpp_noexcept_function_type.
+
+2016-11-07 Martin Liska <mliska@suse.cz>
+
+ * c-warn.c (warn_for_unused_label): Save all labels used
+ in goto or in &label.
+
+2016-11-03 Jason Merrill <jason@redhat.com>
+
+ * c-cppbuiltin.c (c_cpp_builtins): Correct
+ __cpp_inheriting_constructors.
+
+2016-11-01 Jason Merrill <jason@redhat.com>
+
+ * c-cppbuiltin.c (c_cpp_builtins): Update
+ __cpp_inheriting_constructors.
+
+ * c.opt (-fnew-inheriting-ctors): New.
+ * c-opts.c: Default to on for ABI 11+.
+
+2016-10-31 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/77948
+ * c.opt (fext-numeric-literals): Add Var and Init.
+ * c-opts.c (c_common_handle_option): Don't clear
+ cpp_opts->ext_numeric_literals for -std=c++{11,14,1z}.
+ (c_common_post_options): Clear it here if not set
+ explicitly.
+
+2016-10-28 Aldy Hernandez <aldyh@redhat.com>
+
+ PR debug/77773
+ * c-pretty-print.c (simple_type_specifier): Do not dereference `t'
+ if NULL.
+
+2016-10-25 Jakub Jelinek <jakub@redhat.com>
+
+ * c-common.h (enum rid): Add RID_BUILTIN_LAUNDER.
+ * c-common.c (c_common_reswords): Add __builtin_launder.
+
+2016-10-24 Bernd Edlinger <bernd.edlinger@hotmail.de>
+
+ * c-common.c (c_common_truthvalue_conversion): Warn for
+ multiplications in boolean context. Fix the quoting of '<<' and '<'
+ in the shift warning.
+
+2016-10-20 Bernd Edlinger <bernd.edlinger@hotmail.de>
+
+ * c-common.c (c_common_truthvalue_conversion): Fix the comment.
+
+2016-10-20 Jason Merrill <jason@redhat.com>
+
+ * c-cppbuiltin.c (c_cpp_builtins): Update __cpp_concepts value.
+
+2016-10-19 Bernd Edlinger <bernd.edlinger@hotmail.de>
+
+ * c-common.c (c_common_truthvalue_conversion): Warn only for signed
+ integer shift ops in boolean context.
+
+2016-10-18 Aldy Hernandez <aldyh@redhat.com>
+
+ * c.opt (Walloca): New.
+ (Walloca-larger-than=): New.
+ (Wvla-larger-than=): New.
+
+2016-10-17 Marek Polacek <polacek@redhat.com>
+
+ * c-warn.c (find_array_ref_with_const_idx_r): Remove parameter names.
+ Return immediately when finding a match.
+ (warn_tautological_cmp): Remove a boolean variable that is no longer
+ needed.
+
+2016-10-17 Marek Polacek <polacek@redhat.com>
+
+ * c-attribs.c: New file.
+ * c-common.c: Move attributes handling to c-attribs.c.
+ (get_nonnull_operand): No longer static.
+ * c-common.h: Move the declarations from c-attribs.c to its own section.
+
+2016-10-14 Jason Merrill <jason@redhat.com>
+
+ * c-cppbuiltin.c (c_cpp_builtins): Define __cpp_aggregate_bases
+ and __cpp_deduction_guides.
+
+2016-10-13 Jason Merrill <jason@redhat.com>
+
+ * c-cppbuiltin.c (c_cpp_builtins): Add __cpp_inline_variables.
+
+2016-10-13 Thomas Preud'homme <thomas.preudhomme@arm.com>
+
+ * c-cppbuiltin.c: Include memmodel.h.
+ * c-opts.c: Likewise.
+ * c-pragma.c: Likewise.
+ * c-warn.c: Likewise.
+
+2016-10-12 Jakub Jelinek <jakub@redhat.com>
+
+ * c.opt (Wextra): Add as C/C++/ObjC/ObjC++ option.
+ (Wimplicit-fallthrough=): Enable for these languages by -Wextra.
+ * c-opts.c (sanitize_cpp_opts): Initialize
+ cpp_opts->cpp_warn_implicit_fallthrough.
+
+2016-10-11 Marek Polacek <polacek@redhat.com>
+
+ * c-common.c (warning_candidate_p): Change the return type to bool
+ and return true/false instead of 1/0.
+ (vector_mode_valid_p): Likewise.
+
+2016-10-11 Marek Polacek <polacek@redhat.com>
+
+ * c-common.c (fold_for_warn): No longer static.
+ (bool_promoted_to_int_p): Likewise.
+ (c_common_get_narrower): Likewise.
+ (constant_expression_warning): Move to c-warn.c.
+ (constant_expression_error): Likewise.
+ (overflow_warning): Likewise.
+ (warn_logical_operator): Likewise.
+ (find_array_ref_with_const_idx_r): Likewise.
+ (warn_tautological_cmp): Likewise.
+ (expr_has_boolean_operands_p): Likewise.
+ (warn_logical_not_parentheses): Likewise.
+ (warn_if_unused_value): Likewise.
+ (strict_aliasing_warning): Likewise.
+ (sizeof_pointer_memaccess_warning): Likewise.
+ (check_main_parameter_types): Likewise.
+ (conversion_warning): Likewise.
+ (warnings_for_convert_and_check): Likewise.
+ (match_case_to_enum_1): Likewise.
+ (match_case_to_enum): Likewise.
+ (c_do_switch_warnings): Likewise.
+ (warn_for_omitted_condop): Likewise.
+ (readonly_error): Likewise.
+ (lvalue_error): Likewise.
+ (invalid_indirection_error): Likewise.
+ (warn_array_subscript_with_type_char): Likewise.
+ (warn_about_parentheses): Likewise.
+ (warn_for_unused_label): Likewise.
+ (warn_for_div_by_zero): Likewise.
+ (warn_for_memset): Likewise.
+ (warn_for_sign_compare): Likewise.
+ (do_warn_double_promotion): Likewise.
+ (do_warn_unused_parameter): Likewise.
+ (record_locally_defined_typedef): Likewise.
+ (maybe_record_typedef_use): Likewise.
+ (maybe_warn_unused_local_typedefs): Likewise.
+ (maybe_warn_bool_compare): Likewise.
+ (maybe_warn_shift_overflow): Likewise.
+ (warn_duplicated_cond_add_or_warn): Likewise.
+ (diagnose_mismatched_attributes): Likewise.
+ * c-common.h: Move the declarations from c-warn.c to its own section.
+ * c-warn.c: New file.
+
+2016-10-08 Jason Merrill <jason@redhat.com>
+
+ * c-common.c (c_common_truthvalue_conversion): Don't distribute
+ into COND_EXPR in C++.
+
+2016-10-08 Jakub Jelinek <jakub@redhat.com>
+
+ * c-lex.c (c_lex_with_flags) <case CPP_COMMENT>: For CPP_COMMENT
+ token with PREV_FALLTHROUGH, skip all following CPP_PADDING and
+ CPP_COMMENT tokens and set add_flags to PREV_FALLTHROUGH afterwards.
+
+2016-10-07 Jakub Jelinek <jakub@redhat.com>
+
+ Implement LWG2296 helper intrinsic
+ * c-common.h (enum rid): Add RID_ADDRESSOF.
+ * c-common.c (c_common_reswords): Add __builtin_addressof.
+
+2016-10-07 Bernd Edlinger <bernd.edlinger@hotmail.de>
+
+ PR c++/77700
+ * c-common.c (c_common_truthvalue_conversion): Warn also for
+ suspicious enum values in boolean context.
+
+2016-10-06 Jakub Jelinek <jakub@redhat.com>
+
+ Implement P0258R2 - helper for C++17
+ std::has_unique_object_representations trait
+ * c-common.h (enum rid): Add RID_HAS_UNIQUE_OBJ_REPRESENTATIONS.
+ * c-common.c (c_common_reswords): Add
+ __has_unique_object_representations.
+
+2016-10-05 Jakub Jelinek <jakub@redhat.com>
+
+ PR sanitizer/66343
+ * c-ubsan.c (ubsan_instrument_return): Don't call
+ initialize_sanitizer_builtins here.
+
+2016-10-05 Bernd Edlinger <bernd.edlinger@hotmail.de>
+
+ * c-common.c (c_common_truthvalue_conversion): Warn also for suspicious
+ conditional expression in boolean context when only one arm is
+ non-boolean.
+
+2016-10-05 Jakub Jelinek <jakub@redhat.com>
+
+ PR sanitizer/77823
+ * c-ubsan.c (ubsan_instrument_shift): Return NULL_TREE if type0
+ is not integral.
+
+ * c-common.c (c_common_reswords): Update comment for C++11.
+
+2016-10-04 Jason Merrill <jason@redhat.com>
+
+ * c-common.c (make_tree_vector_from_ctor): New.
+ * c-common.h: Declare it.
+
+2016-10-04 Jakub Jelinek <jakub@redhat.com>
+
+ * c-cppbuiltin.c (c_cpp_builtins): Don't define
+ __LIBGCC_JCR_SECTION_NAME__.
+
+2016-10-03 Bernd Edlinger <bernd.edlinger@hotmail.de>
+
+ * c-common.c (c_common_truthvalue_conversion): Warn for suspicious
+ left shift in boolean context.
+
+2016-09-29 Jakub Jelinek <jakub@redhat.com>
+
+ Implement P0001R1 - C++17 removal of register storage class specifier
+ * c.opt (Wregister): New warning.
+ * c-opts.c (c_common_post_options): Enable -Wregister by
+ default for C++17.
+
+2016-09-29 James Greenhalgh <james.greenhalgh@arm.com>
+
+ * c-opts.c (c_common_post_options): Remove special case for
+ TARGET_FLT_EVAL_METHOD_NON_DEFAULT with -fexcess-precision=standard
+ in C++.
+
+2016-09-27 Jakub Jelinek <jakub@redhat.com>
+
+ * c-cppbuiltin.c (c_cpp_builtins): Define __cpp_capture_star_this for
+ -std=c++1z.
+
+ * c-ada-spec.c (print_ada_declaration): Remove break after return.
+
+2016-09-26 Thomas Preud'homme <thomas.preudhomme@arm.com>
+
+ * c-common.c: Include memmodel.h.
+
+2016-09-26 Marek Polacek <polacek@redhat.com>
+
+ * c-lex.c (c_common_has_attribute): Handle attribute fallthrough.
+
+2016-09-26 Marek Polacek <polacek@redhat.com>
+
+ PR c/7652
+ * c-common.c (c_common_attribute_table): Add fallthrough attribute.
+ (handle_fallthrough_attribute): New function.
+ (attribute_fallthrough_p): New function.
+ * c-common.h (attribute_fallthrough_p): Declare.
+
+2016-09-24 Marek Polacek <polacek@redhat.com>
+
+ PR c/77490
+ * c.opt (Wbool-operation): New.
+
+2016-09-21 Bernd Edlinger <bernd.edlinger@hotmail.de>
+
+ * c-common.c (c_common_truthvalue_conversion): Inhibit
+ Wint-in-bool-context warning with from_macro_definition_at.
+ Mention the expression will always evaluate to true.
+
+2016-09-21 Martin Sebor <msebor@redhat.com>
+
+ PR bootstrap/77676
+ * c.opt (fprintf-return-value): Temporarily initialize to zero
+ to unblock bootstrap failures.
+
+2016-09-21 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/77651
+ * c.opt (Waligned-new=): Add RejectNegative.
+ (faligned-new=): Likewise. Spelling fix - change
+ aligned_new_threshhold to aligned_new_threshold.
+ * c-cppbuiltin.c (c_cpp_builtins): Change aligned_new_threshhold
+ to aligned_new_threshold.
+
+2016-09-20 Martin Sebor <msebor@redhat.com>
+
+ PR middle-end/49905
+ * c.opt: Add -Wformat-length and -fprintf-return-value.
+
+2016-09-19 Bernd Edlinger <bernd.edlinger@hotmail.de>
+
+ PR c++/77434
+ * c.opt (Wint-in-bool-context): New warning.
+ * c-common.c (c_common_truthvalue_conversion): Warn on integer
+ constants in boolean context.
+
+2016-09-19 Joseph Myers <joseph@codesourcery.com>
+
+ * c-common.c (max_align_t_align): Also consider alignment of
+ float128_type_node.
+
+2016-09-15 Jason Merrill <jason@redhat.com>
+
+ * c-common.c (check_cxx_fundamental_alignment_constraints): Check
+ DECL_EXTERNAL.
+
+2016-09-14 Jason Merrill <jason@redhat.com>
+
+ * c-common.c (check_cxx_fundamental_alignment_constraints): Don't
+ limit FIELD_DECL, either.
+
+2016-09-14 Marek Polacek <polacek@redhat.com>
+
+ * c-common.c (c_common_truthvalue_conversion): Use false instead of 0.
+ * c-common.h (build_unary_op): Change nonconvert parameter type to bool.
+ * c-omp.c (c_finish_omp_atomic): Use false instead of 0.
+
+2016-09-13 David Malcolm <dmalcolm@redhat.com>
+
+ * c-common.c (warn_logical_not_parentheses): Replace
+ rich_location::add_fixit_insert calls with add_fixit_insert_before
+ and add_fixit_insert_after, eliminating the "next_loc" calculation.
+
+2016-09-13 Jason Merrill <jason@redhat.com>
+ Tom de Vries <tom@codesourcery.com>
+
+ PR c++/77427
+ * c-common.c (set_underlying_type): Don't treat array as builtin type.
+
+2016-09-13 Jason Merrill <jason@redhat.com>
+
+ * c-common.c (check_cxx_fundamental_alignment_constraints): Don't
+ limit types at all.
+
+2016-09-12 Jason Merrill <jason@redhat.com>
+
+ * c-common.c (check_cxx_fundamental_alignment_constraints): Fix
+ bit/byte confusion, allow large alignment for types.
+
+2016-09-12 Bernd Edlinger <bernd.edlinger@hotmail.de>
+
+ PR c++/77496
+ * c-common.c (warn_for_omitted_condop): Also warn for boolean data.
+
+2016-09-12 David Malcolm <dmalcolm@redhat.com>
+
+ PR c/72858
+ * c-format.c (argument_parser::check_argument_type): Add params
+ "type_start" and "conversion_char". Use the former to generate
+ offset_to_type_start and pass it and conversion_char to
+ check_format_types.
+ (check_format_info_main): Capture the start of the type
+ information as "type_start", and pass it an format_char
+ to arg_parser.check_argument_type.
+ (check_format_types): Provide an example in the leading comment.
+ Add params "offset_to_type_start" and "conversion_char"; pass
+ them to format_type_warning calls.
+ (test_get_modifier_for_format_len): Likewise.
+ (matching_type_p): New function.
+ (get_format_for_type): Add param "conversion_char" and move
+ implementation into...
+ (get_format_for_type_1): ...new function, called twice.
+ Use new function matching_type_p rather than checking for
+ TYPE_CANONICAL equality.
+ (get_corrected_substring): New function.
+ (format_type_warning): Provide an example in the leading comment.
+ Add params "offset_to_type_start" and "conversion_char". Replace
+ call to get_format_for_type with call to get_corrected_substring
+ and move rejection of hints for widths/precisions there.
+ (assert_format_for_type_streq): Add param "conversion_char".
+ (ASSERT_FORMAT_FOR_TYPE_STREQ): Add param CONVERSION_CHAR.
+ (test_get_format_for_type_printf): Add conversion chars to the
+ tests, adding coverage for various combinations of integer
+ vs double conversions, and for preserving octal and hexadecimal
+ conversions.
+ (test_get_format_for_type_scanf): Add conversion chars to the
+ tests.
+
+2016-09-10 Tom de Vries <tom@codesourcery.com>
+
+ PR C/71602
+ * c-common.c (build_va_arg): Handle more strict
+ targetm.canonical_va_list_type. Replace first argument type error with
+ assert.
+
+2016-09-09 Martin Sebor <msebor@redhat.com>
+
+ PR c/77520
+ PR c/77521
+ * c-format.c (argument_parser::find_format_char_info): Use %qc
+ format directive unconditionally.
+
+2016-09-09 Jason Merrill <jason@redhat.com>
+
+ Implement C++17 new of over-aligned types.
+ * c.opt: Add -faligned-new and -Waligned-new.
+ * c-common.c (max_align_t_align): Split out from...
+ (cxx_fundamental_alignment_p): ...here.
+ * c-common.h: Declare it.
+ * c-cppbuiltin.c (c_cpp_builtins): Handle aligned new.
+
+2016-09-09 Joseph Myers <joseph@codesourcery.com>
+
+ * c-cppbuiltin.c (builtin_define_type_width): New function.
+ (builtin_define_stdint_macros, c_cpp_builtins): Define type width
+ macros.
+
+2016-09-07 David Malcolm <dmalcolm@redhat.com>
+
+ * c-common.c (get_cpp_ttype_from_string_type): Handle being passed
+ a POINTER_TYPE.
+ (substring_loc::get_location): Move to substring-locations.c,
+ keeping implementation as...
+ (c_get_substring_location): New function, from the above, reworked
+ to use accessors rather than member lookup.
+ * c-common.h (class substring_loc): Move to substring-locations.h,
+ replacing with a forward decl.
+ (c_get_substring_location): New decl.
+ * c-format.c: Include "substring-locations.h".
+ (format_warning_va): Move to substring-locations.c.
+ (format_warning_at_substring): Likewise.
+
+2016-09-06 Martin Sebor <msebor@redhat.com>
+
+ PR c/77336
+ * c-format.c (check_function_format): Avoid issuing warnings for
+ functions unless they call format functions with non-constant
+ format strings.
+
+2016-09-06 Richard Biener <rguenther@suse.de>
+
+ PR c/77450
+ * c-common.c (c_common_mark_addressable_vec): Handle
+ COMPOUND_LITERAL_EXPR.
+
+2016-09-05 Marek Polacek <polacek@redhat.com>
+
+ PR c/77423
+ * c-common.c (bool_promoted_to_int_p): New function.
+ (expr_has_boolean_operands_p): New function.
+ (warn_logical_not_parentheses): Return if expr_has_boolean_operands_p.
+ (maybe_warn_bool_compare): Use bool_promoted_to_int_p.
+
+2016-09-04 Tom de Vries <tom@codesourcery.com>
+
+ revert:
+ 2016-08-29 Tom de Vries <tom@codesourcery.com>
+
+ * c-common.c (build_va_arg): Replace first argument type error
+ with assert.
+
+2016-09-02 Jakub Jelinek <jakub@redhat.com>
+
+ PR c/65467
+ * c-omp.c (c_finish_omp_atomic): Reject _Atomic qualified expressions.
+ (c_finish_omp_for): Reject _Atomic qualified iterators.
+
+2016-09-01 Martin Sebor <msebor@redhat.com>
+
+ * c-ada-spec.c (dump_ada_function_declaration): Increase buffer
+ size to guarantee it fits the output of the formatted function
+ regardless of its arguments.
+
+2016-09-01 Marek Polacek <polacek@redhat.com>
+
+ PR c/7652
+ * c-common.c (resolve_overloaded_builtin): Fix formatting. Add
+ FALLTHRU comments.
+
+2016-08-29 Marek Polacek <polacek@redhat.com>
+
+ PR c/77292
+ * c-common.c (warn_logical_not_parentheses): Don't warn for
+ a comparison or a logical operator.
+
+2016-08-29 Tom de Vries <tom@codesourcery.com>
+
+ * c-common.c (build_va_arg): Fix type comparison assert.
+
+2016-08-29 Tom de Vries <tom@codesourcery.com>
+
+ * c-common.c (build_va_arg): Replace first argument type error
+ with assert.
+
+2016-08-29 Tom de Vries <tom@codesourcery.com>
+
+ PR c/77398
+ * c-common.c (build_va_arg): Add first argument error. Build va_arg
+ with error_mark_node as va_list instead of with illegal va_list.
+
+2016-08-25 Marek Polacek <polacek@redhat.com>
+ David Malcolm <dmalcolm@redhat.com>
+
+ * c-common.c (warn_logical_not_parentheses): Print fixit hints.
+ * c-common.h (warn_logical_not_parentheses): Update declaration.
+
+2016-08-22 Marek Polacek <polacek@redhat.com>
+
+ PR c++/77321
+ * c-common.c (warn_for_memset): Check type for null.
+
+2016-08-22 Joseph Myers <joseph@codesourcery.com>
+
+ * c-family/c-cppbuiltin.c (c_cpp_builtins): Check _FloatN and
+ _FloatNx types for suffixes for built-in functions.
+
+2016-08-19 Joseph Myers <joseph@codesourcery.com>
+
+ PR c/32187
+ * c-common.h (RID_FLOAT16, RID_FLOATN_NX_FIRST, RID_FLOAT32)
+ (RID_FLOAT64, RID_FLOAT128, RID_FLOAT32X, RID_FLOAT64X)
+ (RID_FLOAT128X): New enum rid values.
+ (CASE_RID_FLOATN_NX): New macro.
+ * c-common.c (c_common_reswords): Add _FloatN and _FloatNx
+ keywords.
+ (c_common_type_for_mode): Check for _FloatN and _FloatNx and
+ corresponding complex types.
+ (c_common_nodes_and_builtins): For non-C++, register _FloatN and
+ _FloatNx and corresponding complex types.
+ (keyword_begins_type_specifier): Use CASE_RID_FLOATN_NX.
+ * c-cppbuiltin.c (builtin_define_float_constants): Check _FloatN
+ and _FloatNx types for the widest type for determining
+ DECIMAL_DIG. Define __LDBL_DECIMAL_DIG__ as well as
+ __DECIMAL_DIG__ for long double. Handle FMA_SUFFIX being NULL.
+ (c_cpp_builtins): Call builtin_define_float_constants for _FloatN
+ and _FloatNx types.
+ * c-lex.c (interpret_float): Handle _FloatN and _FloatNx
+ constants.
+ * c-pretty-print.c (pp_c_floating_constant): Handle _FloatN and
+ _FloatNx types.
+
+2016-08-18 David Malcolm <dmalcolm@redhat.com>
+
+ * c-opts.c (c_diagnostic_finalizer): Update for change to
+ diagnostic_show_locus.
+
+2016-08-18 David Malcolm <dmalcolm@redhat.com>
+
+ * c-common.c: Include "spellcheck.h".
+ (cb_get_suggestion): New function.
+ * c-common.h (cb_get_suggestion): New decl.
+ * c-lex.c (init_c_lex): Initialize cb->get_suggestion to
+ cb_get_suggestion.
+
+2016-08-18 Marek Polacek <polacek@redhat.com>
+
+ PR c/71514
+ * c-common.c (get_atomic_generic_size): Disallow pointer-to-function
+ and pointer-to-VLA.
+
+2016-08-16 David Malcolm <dmalcolm@redhat.com>
+
+ PR c/72857
+ * c-common.c (substring_loc::get_range): Rename to...
+ (substring_loc::get_location): ...this, converting param from a
+ source_range * to a location_t *. Call
+ get_source_location_for_substring rather than
+ get_source_range_for_substring, and pass in m_caret_idx.
+ * c-common.h (substring_loc::substring_loc): Add param "caret_idx".
+ (substring_loc::get_range): Replace with...
+ (substring_loc::get_location): ...this.
+ (substring_loc::set_caret_index): New method.
+ (substring_loc): Add field m_caret_idx.
+ * c-format.c (format_warning_va): Update for above changes.
+ Rename local "substring_loc" to "fmt_substring_loc" to avoid
+ clashing with type name.
+ (format_warning_at_char): Add caret_idx param to substring_loc ctor.
+ (check_argument_type): Likewise.
+ (format_type_warning): Rename param "fmt_loc" to "whole_fmt_loc"
+ Use a copy when emitting warnings, setting the caret index from TYPE.
+
+2016-08-16 Eric Botcazou <ebotcazou@adacore.com>
+ Arnaud Charlet <charlet@adacore.com>
+
+ * c-ada-spec.c (dump_number): New function.
+ (handle_escape_character): Likewise.
+ (print_ada_macros): Add handling of constant integers and strings.
+
+2016-08-12 Marek Polacek <polacek@redhat.com>
+
+ PR c/7652
+ * c-common.c (scalar_to_vector): Adjust fall through comment.
+ * c-opts.c (c_common_handle_option): Likewise.
+ * c-pragma.c (handle_pragma_pack): Add FALLTHRU.
+ * c-pretty-print.c (c_pretty_printer::postfix_expression): Adjust
+ fall through comment.
+ * cilk.c (extract_free_variables): Add FALLTHRU.
+
+2016-08-10 Jason Merrill <jason@redhat.com>
+
+ * c-cppbuiltin.c (c_cpp_builtins): Define __cpp_if_constexpr.
+
+2016-08-09 Jason Merrill <jason@redhat.com>
+
+ * c-common.c (c_common_attribute_table): vector_size affects type
+ identity.
+
+2016-08-09 Marek Polacek <polacek@redhat.com>
+
+ PR c/7652
+ * c-ada-spec.c (dump_generic_ada_node): Add return.
+
+2016-08-09 Jason Merrill <jason@redhat.com>
+
+ * c-cppbuiltin.c (c_cpp_builtins): Update __cpp_constexpr for
+ C++17 constexpr lambdas.
+
+2016-08-08 David Malcolm <dmalcolm@redhat.com>
+
+ PR c/64955
+ * c-common.h (selftest::c_format_c_tests): New declaration.
+ (selftest::run_c_tests): New declaration.
+ * c-format.c: Include "selftest.h.
+ (format_warning_va): Add param "corrected_substring" and use
+ it to add a replacement fix-it hint.
+ (format_warning_at_substring): Likewise.
+ (format_warning_at_char): Update for new param of
+ format_warning_va.
+ (argument_parser::check_argument_type): Pass "fki" to
+ check_format_types.
+ (check_format_types): Add param "fki" and pass it to
+ format_type_warning.
+ (deref_n_times): New function.
+ (get_modifier_for_format_len): New function.
+ (selftest::test_get_modifier_for_format_len): New function.
+ (get_format_for_type): New function.
+ (format_type_warning): Add param "fki" and use it to attempt
+ to provide hints for argument types when calling
+ format_warning_at_substring.
+ (selftest::get_info): New function.
+ (selftest::assert_format_for_type_streq): New function.
+ (ASSERT_FORMAT_FOR_TYPE_STREQ): New macro.
+ (selftest::test_get_format_for_type_printf): New function.
+ (selftest::test_get_format_for_type_scanf): New function.
+ (selftest::c_format_c_tests): New function.
+
+2016-08-08 David Malcolm <dmalcolm@redhat.com>
+
+ PR c/52952
+ * c-format.c: Include "diagnostic.h".
+ (location_column_from_byte_offset): Delete.
+ (location_from_offset): Delete.
+ (format_warning_va): New function.
+ (format_warning_at_substring): New function.
+ (format_warning_at_char): New function.
+ (check_format_arg): Capture location of format_tree and pass to
+ check_format_info_main.
+ (argument_parser): Add fields "start_of_this_format" and
+ "format_string_cst".
+ (flag_chars_t::validate): Add param "format_string_cst". Convert
+ warning_at call using location_from_offset to call to
+ format_warning_at_char.
+ (argument_parser::argument_parser): Add param "format_string_cst_"
+ and use use it to initialize field "format_string_cst".
+ Initialize new field "start_of_this_format".
+ (argument_parser::read_format_flags): Convert warning_at call
+ using location_from_offset to a call to format_warning_at_char.
+ (argument_parser::read_any_format_left_precision): Likewise.
+ (argument_parser::read_any_format_precision): Likewise.
+ (argument_parser::read_any_other_modifier): Likewise.
+ (argument_parser::find_format_char_info): Likewise, in three places.
+ (argument_parser::parse_any_scan_set): Likewise, in one place.
+ (argument_parser::handle_conversions): Likewise, in two places.
+ (argument_parser::check_argument_type): Add param "fmt_param_loc"
+ and use it to make a substring_loc. Pass the latter to
+ check_format_types.
+ (check_format_info_main): Add params "fmt_param_loc" and
+ "format_string_cst". Convert warning_at calls using
+ location_from_offset to calls to format_warning_at_char. Pass the
+ new params to the arg_parser ctor. Pass "format_string_cst" to
+ flag_chars.validate. Pass "fmt_param_loc" to
+ arg_parser.check_argument_type.
+ (check_format_types): Convert first param from a location_t
+ to a const substring_loc & and rename to "fmt_loc". Attempt
+ to extract the range of the relevant parameter and pass it
+ to format_type_warning.
+ (format_type_warning): Convert first param from a location_t
+ to a const substring_loc & and rename to "fmt_loc". Add
+ params "param_range" and "type". Replace calls to warning_at
+ with calls to format_warning_at_substring.
+
+2016-08-08 David Malcolm <dmalcolm@redhat.com>
+
+ * c-format.c (class flag_chars_t): New class.
+ (struct length_modifier): New struct.
+ (class argument_parser): New class.
+ (flag_chars_t::flag_chars_t): New ctor.
+ (flag_chars_t::has_char_p): New method.
+ (flag_chars_t::add_char): New method.
+ (flag_chars_t::validate): New method.
+ (flag_chars_t::get_alloc_flag): New method.
+ (flag_chars_t::assignment_suppression_p): New method.
+ (argument_parser::argument_parser): New ctor.
+ (argument_parser::read_any_dollar): New method.
+ (argument_parser::read_format_flags): New method.
+ (argument_parser::read_any_format_width): New method.
+ (argument_parser::read_any_format_left_precision): New method.
+ (argument_parser::read_any_format_precision): New method.
+ (argument_parser::handle_alloc_chars): New method.
+ (argument_parser::read_any_length_modifier): New method.
+ (argument_parser::read_any_other_modifier): New method.
+ (argument_parser::find_format_char_info): New method.
+ (argument_parser::validate_flag_pairs): New method.
+ (argument_parser::give_y2k_warnings): New method.
+ (argument_parser::parse_any_scan_set): New method.
+ (argument_parser::handle_conversions): New method.
+ (argument_parser::check_argument_type): New method.
+ (check_format_info_main): Introduce classes argument_parser
+ and flag_chars_t, moving the code within the loop into methods
+ of these classes. Make various locals "const".
+
+2016-08-05 David Malcolm <dmalcolm@redhat.com>
+
+ * c-common.c: Include "substring-locations.h".
+ (get_cpp_ttype_from_string_type): New function.
+ (g_string_concat_db): New global.
+ (substring_loc::get_range): New method.
+ * c-common.h (g_string_concat_db): New declaration.
+ (class substring_loc): New class.
+ * c-lex.c (lex_string): When concatenating strings, capture the
+ locations of all tokens using a new obstack, and record the
+ concatenation locations within g_string_concat_db.
+ * c-opts.c (c_common_init_options): Construct g_string_concat_db
+ on the ggc-heap.
+
+2016-07-29 Marek Polacek <polacek@redhat.com>
+
+ PR c/71926
+ * c-common.c (c_common_truthvalue_conversion): Use LOCATION for the
+ parentheses warning.
+
+ PR c/71574
+ * c-common.c (handle_alloc_align_attribute): Also check FUNCTION_DECL.
+
+2016-07-28 Martin Liska <mliska@suse.cz>
+
+ PR gcov-profile/68025
+ * c-common.c (handle_no_profile_instrument_function_attribute):
+
+2016-07-27 Bernd Edlinger <bernd.edlinger@hotmail.de>
+
+ * c-common.c (check_user_alignment): Use LOG2_BITS_PER_UNIT instead of
+ BITS_PER_UNIT_LOG.
+
+2016-07-25 Jason Merrill <jason@redhat.com>
+
+ PR c++/65970
+ * c.opt (fconstexpr-loop-limit): New.
+
+2016-07-22 Martin Sebor <msebor@redhat.com>
+
+ PR c++/71675
+ * c-common.c (resolve_overloaded_builtin): Avoid converting
+ __atomic_compare_exchange_n return type to that of what its
+ first argument points to.
+
+2016-07-22 Uros Bizjak <ubizjak@gmail.com>
+
+ * c-common.c: Use HOST_WIDE_INT_M1U instead of
+ ~(unsigned HOST_WIDE_INT) 0.
+
+2016-07-22 Martin Liska <mliska@suse.cz>
+
+ PR gcov-profile/69028
+ PR gcov-profile/62047
+ * cilk.c (create_cilk_helper_decl): Set location of a new decl
+ to the current_function_decl.
+
+2016-07-21 Jason Merrill <jason@redhat.com>
+
+ PR c++/65168
+ * c-common.c (c_common_truthvalue_conversion): Check
+ c_inhibit_evaluation_warnings for warning about address of
+ reference.
+
+2016-07-20 David Malcolm <dmalcolm@redhat.com>
+
+ * c-common.h (lookup_name_fuzzy): Convert return type from tree to
+ const char *.
+
+2016-07-15 Jason Merrill <jason@redhat.com>
+
+ * c-opts.c (c_common_post_options): Update -fabi-version default to 11.
+
+2016-07-15 Jakub Jelinek <jakub@redhat.com>
+
+ PR c/71858
+ * c-common.h (enum lookup_name_fuzzy_kind): Add
+ FUZZY_LOOKUP_FUNCTION_NAME.
+
+2016-07-08 Jason Merrill <jason@redhat.com>
+
+ P0145: Refining Expression Order for C++.
+ * c.opts (-fargs-in-order): Rename to -fstrong-eval-order.
+ * c-opts.c: Adjust.
2016-07-05 Markus Trippelsdorf <markus@trippelsdorf.de>
PR c++/71214
* c-cppbuiltin.c (c_cpp_builtins): Define __cpp_rvalue_references.
-2016-06-14 Jakub Jelinek <jakub@redhat.com>
+2016-06-29 Thomas Schwinge <thomas@codesourcery.com>
- Backported from mainline
- 2016-06-10 Jakub Jelinek <jakub@redhat.com>
+ * c-pragma.h (enum pragma_kind): Rename
+ PRAGMA_OMP_DECLARE_REDUCTION to PRAGMA_OMP_DECLARE. Adjust all
+ users.
- PR c/68657
- * c.opt (Wpsabi): Add Warning flag.
+2016-06-29 Richard Biener <rguenther@suse.de>
+
+ PR middle-end/71002
+ * c-common.c (c_common_get_alias_set): Remove union type punning case.
+
+2016-06-24 Jason Merrill <jason@redhat.com>
+
+ P0145R2: Refining Expression Order for C++.
+ * c-common.c (verify_tree) [COMPOUND_EXPR]: Fix handling on LHS of
+ MODIFY_EXPR.
+
+2016-06-24 Jakub Jelinek <jakub@redhat.com>
+
+ * c-common.c (check_builtin_function_arguments): Require last
+ argument of BUILT_IN_*_OVERFLOW_P to have INTEGER_TYPE type.
+ Adjust wording of diagnostics for BUILT_IN_*_OVERLFLOW
+ if the last argument is pointer to enumerated or boolean type.
+
+2016-06-22 David Malcolm <dmalcolm@redhat.com>
+
+ PR c/70339
+ * c-common.h (enum lookup_name_fuzzy_kind): New enum.
+ (lookup_name_fuzzy): New prototype.
+
+2016-06-21 John David Anglin <danglin@gcc.gnu.org>
+
+ * c-common.c (get_source_date_epoch): Use int64_t instead of long long.
+
+2016-06-14 Jason Merrill <jason@redhat.com>
+
+ P0145R2: Refining Expression Order for C++.
+ * c.opt (fargs-in-order): New.
+ * c-opts.c (c_common_post_options): Adjust flag_args_in_order.
2016-06-13 Jakub Jelinek <jakub@redhat.com>
@@ -21,6 +1258,60 @@
* c-gimplify.c (ubsan_walk_array_refs_r): Set *walk_subtrees = 0 on
all BIND_EXPRs, and on all BIND_EXPRs recurse also on BIND_EXPR_BODY.
+ PR preprocessor/71183
+ * c-ppoutput.c (init_pp_output): Set cb->get_source_date_epoch
+ to cb_get_source_date_epoch.
+
+2016-06-10 Jakub Jelinek <jakub@redhat.com>
+
+ PR c/68657
+ * c.opt (Wpsabi): Add Warning flag.
+
+2016-06-10 Martin Sebor <msebor@redhat.com>
+
+ PR c/71392
+ * gcc/c-family/c-common.c (handle_nonnull_attribute): Accept
+ the nonnull attribute in type-generic builtins.
+
+2016-06-09 Martin Sebor <msebor@redhat.com>
+
+ PR c/70883
+ * c-common.c (builtin_function_validate_nargs): Make text of error
+ message consistent with others like it.
+
+2016-06-08 Martin Sebor <msebor@redhat.com>
+ Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/70507
+ PR c/68120
+ * c-common.c (check_builtin_function_arguments): Handle
+ BUILT_IN_{ADD,SUB,MUL}_OVERFLOW_P.
+
+2016-06-08 Richard Biener <rguenther@suse.de>
+
+ * c-common.c (parse_optimize_options): Improve diagnostic messages.
+
+2016-06-07 Richard Biener <rguenther@suse.de>
+
+ PR c/61564
+ * c-common.c (parse_optimize_options): Only apply CL_OPTIMIZATION
+ options and warn about others.
+
+2016-06-01 Eduard Sanou <dhole@openmailbox.org>
+
+ * c-common.c (get_source_date_epoch): Rename to
+ cb_get_source_date_epoch.
+ * c-common.c (cb_get_source_date_epoch): Use a single generic erorr
+ message when the parsing fails. Use error_at instead of fatal_error.
+ * c-common.h (get_source_date_epoch): Rename to
+ cb_get_source_date_epoch.
+ * c-common.h (cb_get_source_date_epoch): Prototype.
+ * c-common.h (MAX_SOURCE_DATE_EPOCH): Define.
+ * c-common.h (c_omp_region_type): Remove trailing comma.
+ * c-lex.c (init_c_lex): Set cb->get_source_date_epoch callback.
+ * c-lex.c (c_lex_with_flags): Remove initialization of
+ pfile->source_date_epoch.
+
2016-05-30 Jakub Jelinek <jakub@redhat.com>
PR c++/71349
@@ -29,6 +1320,63 @@
C_OMP_CLAUSE_SPLIT_TARGET if combined with target construct,
instead of C_OMP_CLAUSE_SPLIT_FOR.
+2016-05-24 Richard Biener <rguenther@suse.de>
+
+ PR middle-end/70434
+ PR c/69504
+ * c-common.h (convert_vector_to_pointer_for_subscript): Rename to ...
+ (convert_vector_to_array_for_subscript): ... this.
+ * c-common.c (convert_vector_to_pointer_for_subscript): Use a
+ VIEW_CONVERT_EXPR to an array type. Rename to ...
+ (convert_vector_to_array_for_subscript): ... this.
+
+2016-05-12 Marek Polacek <polacek@redhat.com>
+
+ PR c/70756
+ * c-common.c (pointer_int_sum): Call size_in_bytes_loc instead of
+ size_in_bytes and pass LOC to it.
+
+2016-05-11 Mikhail Maltsev <maltsevm@gmail.com>
+
+ PR c/43651
+ * c.opt (Wduplicate-decl-specifier): New option.
+
+2016-05-11 Marek Polacek <polacek@redhat.com>
+
+ PR c++/71024
+ * c-common.c (diagnose_mismatched_attributes): New function.
+ * c-common.h (diagnose_mismatched_attributes): Declare.
+
+2016-05-04 Marek Polacek <polacek@redhat.com>
+
+ * c.opt (Wdangling-else): New option.
+
+2016-05-03 Marek Polacek <polacek@redhat.com>
+
+ PR c/70859
+ * c-common.c (builtin_function_validate_nargs): Add location
+ parameter. Use it.
+ (check_builtin_function_arguments): Add location and arguments
+ parameters. Use them.
+ * c-common.h (check_builtin_function_arguments): Update declaration.
+
+2016-05-03 Richard Biener <rguenther@suse.de>
+
+ * cilk.c (cilk_gimplify_call_params_in_spawned_fn): Do not
+ allow call args to gimplify to SSA names.
+
+2016-05-03 Marek Polacek <polacek@redhat.com>
+
+ * c-common.h (enum c_omp_region_type): Remove stray comma.
+
+2016-05-02 Cesar Philippidis <cesar@codesourcery.com>
+
+ * c-common.h (enum c_omp_region_type): Define.
+
+2016-05-02 Richard Sandiford <richard.sandiford@arm.com>
+
+ * c-common.c (shorten_compare): Use wi::to_wide.
+
2016-04-29 Cesar Philippidis <cesar@codesourcery.com>
PR middle-end/70626
@@ -36,14 +1384,80 @@
* c-omp.c (c_oacc_split_loop_clauses): Use it to duplicate
reduction clauses in acc parallel loops.
-2016-04-27 Release Manager
+2016-04-29 Marek Polacek <polacek@redhat.com>
+
+ PR c/70852
+ * c-common.c (warn_for_memset): Check domain before accessing it.
+
+2016-04-29 Dominik Vogt <vogt@linux.vnet.ibm.com>
+
+ PR/69089
+ * c-common.c (handle_aligned_attribute): Allow 0 as an argument to the
+ "aligned" attribute.
+
+2016-04-28 Jason Merrill <jason@redhat.com>
+
+ * c-lex.c (c_common_has_attribute): Handle nodiscard.
+
+2016-04-28 Eduard Sanou <dhole@openmailbox.org>
+ Matthias Klose <doko@debian.org>
+
+ * c-common.c (get_source_date_epoch): New function, gets the environment
+ variable SOURCE_DATE_EPOCH and parses it as long long with error
+ handling.
+ * c-common.h (get_source_date_epoch): Prototype.
+ * c-lex.c (c_lex_with_flags): set parse_in->source_date_epoch.
+
+2015-04-27 Ryan Burn <contact@rnburn.com>
+
+ PR c++/69024
+ PR c++/68997
+ * cilk.c (cilk_ignorable_spawn_rhs_op): Change to external linkage.
+ (cilk_recognize_spawn): Renamed from recognize_spawn and change to
+ external linkage.
+ (cilk_detect_and_unwrap): Corresponding changes.
+ (extract_free_variables): Don't extract free variables from
+ AGGR_INIT_EXPR slot.
+ * c-common.h (cilk_ignorable_spawn_rhs_op): Prototype.
+ (cilk_recognize_spawn): Likewise.
+
+2016-04-27 Bernd Schmidt <bschmidt@redhat.com>
- * GCC 6.1.0 released.
+ * c.opt (Wmemset-elt-size): New option.
+ * c-common.c (warn_for_memset): New function.
+ * c-common.h (warn_for_memset): Declare.
+
+2016-04-25 Jason Merrill <jason@redhat.com>
+
+ * c-common.c (handle_unused_attribute): Accept CONST_DECL.
+ No longer static.
+ * c-common.h: Declare it.
+ * c-lex.c (c_common_has_attribute): Add maybe_unused.
-2016-04-19 Jason Merrill <jason@redhat.com>
+2016-04-22 Jason Merrill <jason@redhat.com>
* c-cppbuiltin.c (c_cpp_builtins): Fix __cpp_range_based_for.
+2016-04-20 Ilya Verbin <ilya.verbin@intel.com>
+
+ PR c++/69363
+ * c-cilkplus.c (c_finish_cilk_clauses): Remove function.
+ * c-common.h (c_finish_cilk_clauses): Remove declaration.
+
+2016-04-18 Michael Matz <matz@suse.de>
+
+ * c-common.c (handle_aligned_attribute): Use SET_TYPE_ALIGN
+ and SET_DECL_ALIGN.
+
+2016-04-17 Eric Botcazou <ebotcazou@adacore.com>
+
+ * c-ada-spec.c (get_underlying_decl): Return the typedef, if any.
+ (dump_generic_ada_node) <POINTER_TYPE>: Clean up handling of access
+ to incomplete types.
+ (dump_nested_type): Remove redundant tests and tidy up.
+ (print_ada_declaration): Also set TREE_VISITED on the declaration of
+ a type which is the typedef of an original type.
+
2016-04-15 Marek Polacek <polacek@redhat.com>
PR c/70651
@@ -472,7 +1886,7 @@
* c-common.c (valid_array_size_p): New function.
* c-common.h (valid_array_size_p): Declare.
-2015-11-11 Dominique d'Humieres <dominiq@lps.ens.fr>
+2015-11-11 Dominique d'Humieres <dominiq@lps.ens.fr>
PR bootstrap/68271
* c-pragma.c (c_register_pragma_1): Update the gcc_assert to 256.
@@ -581,7 +1995,7 @@
* c-omp.c (c_omp_split_clauses): Remove conditional compilation. Use
flag_checking.
-2015-11-03 Bernd Schmidt <bschmidt@redhat.com>
+2015-11-03 Bernd Schmidt <bschmidt@redhat.com>
PR c++-common/67882
* c-common.h (fold_offsetof_1): Add argument.
@@ -1490,7 +2904,7 @@
before trying to figure out whether we have a flexible array member.
2015-03-06 Eric Botcazou <ebotcazou@adacore.com>
- Jonathan Wakely <jwakely.gcc@gmail.com>
+ Jonathan Wakely <jwakely.gcc@gmail.com>
* c-ada-spec.c (dump_ada_double_name): Fix pasto.
@@ -1635,14 +3049,14 @@
PRAGMA_OACC_CLAUSE_VECTOR_LENGTH, PRAGMA_OACC_CLAUSE_WAIT,
PRAGMA_OACC_CLAUSE_WORKER.
-2015-01-14 Marcos Diaz <marcos.diaz@tallertechnologies.com>
+2015-01-14 Marcos Diaz <marcos.diaz@tallertechnologies.com>
* c-cppbuiltin.c (c_cpp_builtins): New cpp define __SSP_EXPLICIT__
for the new option fstack-protector_explicit.
* c-common.c (c_common_attribute_table): Add stack_protect attribute.
(handle_stack_protect_attribute): New function.
-2015-01-13 Martin Uecker <uecker@eecs.berkeley.edu>
+2015-01-13 Martin Uecker <uecker@eecs.berkeley.edu>
* c.opt: New option -Warray-bounds=.
@@ -1730,7 +3144,7 @@
* c-cppbuiltin.c (__cpp_sized_deallocation): Uncomment and move macro.
Control macro with flag_sized_deallocation.
-2014-12-20 Martin Uecker <uecker@eecs.berkeley.edu>
+2014-12-20 Martin Uecker <uecker@eecs.berkeley.edu>
* c.opt (Wdiscarded-array-qualifiers): New option.
@@ -2715,7 +4129,7 @@
2014-03-08 Paulo Matos <paulo@matos-sorge.com>
- * c.opt: Enable LTO FE for fshort-double.
+ * c.opt: Enable LTO FE for fshort-double.
2014-03-07 Jason Merrill <jason@redhat.com>
@@ -2884,7 +4298,7 @@
(print_destructor): Retrieve the origin of the destructor.
(print_ada_declaration): Revamp handling of constructors/destructors.
-2013-12-23 Stuart Hastings <stuart@apple.com>
+2013-12-23 Stuart Hastings <stuart@apple.com>
Bill Maddox <maddox@google.com>
Jason Merrill <jason@redhat.com>
@@ -3012,15 +4426,15 @@
that lower floating point number precision or about the other
kinds of conversions.
* c-common.h (enum conversion_safety): New enumeration.
- (unsafe_conversion_p): switching return type to
- conversion_safety enumeration.
+ (unsafe_conversion_p): switching return type to
+ conversion_safety enumeration.
* c.opt: Adding new warning -Wfloat-conversion and
enabling it with -Wconversion.
2013-11-19 Basile Starynkevitch <basile@starynkevitch.net>
- * c-opts.c: Include plugin.h.
- (cb_file_change): Invoke plugin event PLUGIN_INCLUDE_FILE.
+ * c-opts.c: Include plugin.h.
+ (cb_file_change): Invoke plugin event PLUGIN_INCLUDE_FILE.
2013-11-19 Marek Polacek <polacek@redhat.com>
@@ -3240,7 +4654,7 @@
2013-10-31 Edward Smith-Rowland <3dw4rd@verizon.net>
- Implement C++14 digit separators.
+ Implement C++14 digit separators.
* c-lex.c (interpret_float): Remove digit separators from scratch string
before building real literal.
@@ -3808,7 +5222,7 @@
__GXX_EXPERIMENTAL_CXX1Y__.
2013-04-24 Paolo Carlini <paolo.carlini@oracle.com>
- Manuel Lopez-Ibanez <manu@gcc.gnu.org>
+ Manuel Lopez-Ibanez <manu@gcc.gnu.org>
* c.opt ([Wpointer-arith]): Enabled by -Wpedantic, as documented.
* c-common.c (pointer_int_sum): Change -Wpointer-arith pedwarns
@@ -3949,7 +5363,7 @@
PR 55139
* c-common.c (get_atomic_generic_size): Mask with
- MEMMODEL_MASK
+ MEMMODEL_MASK
2012-11-07 Manuel López-Ibáñez <manu@gcc.gnu.org>
@@ -3963,16 +5377,16 @@
* c-opts.c (c_common_handle_option): Do not handle Wformat here.
* c-format.c (set_Wformat): Delete.
(decode_format_attr): Replace OPT_Wformat with OPT_Wformat_.
- (maybe_read_dollar_number): Likewise.
- (avoid_dollar_number): Likewise.
- (finish_dollar_format_checking): Likewise.
- (check_format_info): Likewise.
- (check_format_info_main): Likewise.
- (check_format_types): Likewise.
- (format_type_warning): Likewise.
- * c-common.c (int): Likewise.
- (check_function_sentinel): Likewise.
- * c-common.h (warn_format,set_Wformat): Do not declare here.
+ (maybe_read_dollar_number): Likewise.
+ (avoid_dollar_number): Likewise.
+ (finish_dollar_format_checking): Likewise.
+ (check_format_info): Likewise.
+ (check_format_info_main): Likewise.
+ (check_format_types): Likewise.
+ (format_type_warning): Likewise.
+ * c-common.c (int): Likewise.
+ (check_function_sentinel): Likewise.
+ * c-common.h (warn_format,set_Wformat): Do not declare here.
2012-11-07 Manuel López-Ibáñez <manu@gcc.gnu.org>
@@ -4131,11 +5545,11 @@
* c-pch.c (c_common_read_pch): Rebuild the location_adhoc_data
map when read in the pch.
-2012-09-18 Arnaud Charlet <charlet@adacore.com>
+2012-09-18 Arnaud Charlet <charlet@adacore.com>
* c-ada-spec.c: Style fixes.
-2012-09-18 Thomas Quinot <quinot@adacore.com>
+2012-09-18 Thomas Quinot <quinot@adacore.com>
* c.opt (-fada-spec-parent): Define new command line switch.
* c-ada-spec.c (get_ada_package): When -fada-spec-parent
@@ -4858,7 +6272,7 @@
(keyword_is_function_specifier): Handle RID_NORETURN.
* c-common.h (RID_NORETURN): New.
-2011-08-10 Artjoms Sinkarovs <artyom.shinakroff@gmail.com>
+2011-08-10 Artjoms Sinkarovs <artyom.shinakroff@gmail.com>
* c-common.c (unsafe_conversion_p): New function. Check if it is
unsafe to convert an expression to the type.
@@ -5226,7 +6640,7 @@
* c-ada-spec.c (dump_ada_template): Skip non-class instances.
-2011-03-17 Kai Tietz
+2011-03-17 Kai Tietz <ktietz@redhat.com>
PR target/12171
* c-pretty-print.c (pp_c_specifier_qualifier_list):
@@ -5619,8 +7033,8 @@
* 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>
+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.
@@ -5666,7 +7080,7 @@
Merge from 'apple/trunk' branch on FSF servers.
- 2005-11-08 Fariborz Jahanian <fjahanian@apple.com>
+ 2005-11-08 Fariborz Jahanian <fjahanian@apple.com>
Radar 4330422
* c-common.h (objc_non_volatilized_type): New declaration
@@ -5676,7 +7090,7 @@
Merge from 'apple/trunk' branch on FSF servers.
- 2006-03-27 Fariborz Jahanian <fjahanian@apple.com>
+ 2006-03-27 Fariborz Jahanian <fjahanian@apple.com>
Radar 4133425
* c-common.h (objc_diagnose_private_ivar): New decl.
@@ -5701,7 +7115,7 @@
2010-10-14 Iain Sandoe <iains@gcc.gnu.org>
merge from FSF apple 'trunk' branch.
- 2006 Fariborz Jahanian <fjahanian@apple.com>
+ 2006 Fariborz Jahanian <fjahanian@apple.com>
Radars 4436866, 4505126, 4506903, 4517826
* c-common.c (c_common_resword): Define @property and its attributes.
@@ -5718,7 +7132,7 @@
2010-10-13 Iain Sandoe <iains@gcc.gnu.org>
merge from FSF apple 'trunk' branch.
- 2006-04-26 Fariborz Jahanian <fjahanian@apple.com>
+ 2006-04-26 Fariborz Jahanian <fjahanian@apple.com>
Radar 3803157 (method attributes)
* c-common.c (handle_deprecated_attribute): Recognize
@@ -5771,7 +7185,7 @@
and @required keywords.
merge from FSF 'apple/trunk' branch.
- 2006-01-30 Fariborz Jahanian <fjahanian@apple.com>
+ 2006-01-30 Fariborz Jahanian <fjahanian@apple.com>
Radar 4386773
* c-common.h (RID_AT_OPTIONAL, RID_AT_REQUIRED): Two new
@@ -5798,7 +7212,7 @@
Merge from 'apple/trunk' branch on FSF servers.
- 2005-10-04 Fariborz Jahanian <fjahanian@apple.com>
+ 2005-10-04 Fariborz Jahanian <fjahanian@apple.com>
Radar 4281748
* c-common.h (objc_check_global_decl): New declaration.
@@ -5855,7 +7269,7 @@
Merge from 'apple/trunk' branch on FSF servers.
- 2005-12-15 Fariborz Jahanian <fjahanian@apple.com>
+ 2005-12-15 Fariborz Jahanian <fjahanian@apple.com>
Radar 4229905
* c-common.h (objc_have_common_type): New declaration.
@@ -6248,7 +7662,7 @@
* c-common.c: Include gt-c-family-c-common.h.
* c-pragma.c: Include gt-c-family-c-pragma.h.
-Copyright (C) 2010-2016 Free Software Foundation, Inc.
+Copyright (C) 2010-2017 Free Software Foundation, Inc.
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright
diff --git a/gcc/c-family/array-notation-common.c b/gcc/c-family/array-notation-common.c
index 2146d22760..3b95332ada 100644
--- a/gcc/c-family/array-notation-common.c
+++ b/gcc/c-family/array-notation-common.c
@@ -1,7 +1,7 @@
/* This file is part of the Intel(R) Cilk(TM) Plus support
This file contains the builtin functions for Array
notations.
- Copyright (C) 2013-2016 Free Software Foundation, Inc.
+ Copyright (C) 2013-2017 Free Software Foundation, Inc.
Contributed by Balaji V. Iyer <balaji.v.iyer@intel.com>,
Intel Corporation
@@ -621,21 +621,23 @@ cilkplus_extract_an_triplets (vec<tree, va_gc> *list, size_t size, size_t rank,
break;
}
}
- for (size_t ii = 0; ii < size; ii++)
- if (TREE_CODE ((*list)[ii]) == ARRAY_NOTATION_REF)
- for (size_t jj = 0; jj < rank; jj++)
- {
- tree ii_tree = array_exprs[ii][jj];
- (*node)[ii][jj].is_vector = true;
- (*node)[ii][jj].value = ARRAY_NOTATION_ARRAY (ii_tree);
- (*node)[ii][jj].start = ARRAY_NOTATION_START (ii_tree);
- (*node)[ii][jj].length =
- fold_build1 (CONVERT_EXPR, integer_type_node,
+ for (size_t ii = 0; ii < size; ii++)
+ if (TREE_CODE ((*list)[ii]) == ARRAY_NOTATION_REF)
+ for (size_t jj = 0; jj < rank; jj++)
+ {
+ tree ii_tree = array_exprs[ii][jj];
+ (*node)[ii][jj].is_vector = true;
+ (*node)[ii][jj].value = ARRAY_NOTATION_ARRAY (ii_tree);
+ (*node)[ii][jj].start
+ = fold_build1 (CONVERT_EXPR, integer_type_node,
+ ARRAY_NOTATION_START (ii_tree));
+ (*node)[ii][jj].length
+ = fold_build1 (CONVERT_EXPR, integer_type_node,
ARRAY_NOTATION_LENGTH (ii_tree));
- (*node)[ii][jj].stride =
- fold_build1 (CONVERT_EXPR, integer_type_node,
+ (*node)[ii][jj].stride
+ = fold_build1 (CONVERT_EXPR, integer_type_node,
ARRAY_NOTATION_STRIDE (ii_tree));
- }
+ }
release_vec_vec (array_exprs);
}
diff --git a/gcc/c-family/c-ada-spec.c b/gcc/c-family/c-ada-spec.c
index 75a25ccbc6..18c5ccf105 100644
--- a/gcc/c-family/c-ada-spec.c
+++ b/gcc/c-family/c-ada-spec.c
@@ -1,6 +1,6 @@
/* 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-2016 Free Software Foundation, Inc.
+ Copyright (C) 2010-2017 Free Software Foundation, Inc.
Adapted from tree-pretty-print.c by Arnaud Charlet <charlet@adacore.com>
This file is part of GCC.
@@ -72,7 +72,7 @@ macro_length (const cpp_macro *macro, int *supported, int *buffer_len,
if (macro->fun_like)
{
- param_len++;
+ (*param_len)++;
for (i = 0; i < macro->paramc; i++)
{
cpp_hashnode *param = macro->params[i];
@@ -116,6 +116,58 @@ macro_length (const cpp_macro *macro, int *supported, int *buffer_len,
(*buffer_len)++;
}
+/* Dump all digits/hex chars from NUMBER to BUFFER and return a pointer
+ to the character after the last character written. */
+
+static unsigned char *
+dump_number (unsigned char *number, unsigned char *buffer)
+{
+ while (*number != '\0'
+ && *number != 'U'
+ && *number != 'u'
+ && *number != 'l'
+ && *number != 'L')
+ *buffer++ = *number++;
+
+ return buffer;
+}
+
+/* Handle escape character C and convert to an Ada character into BUFFER.
+ Return a pointer to the character after the last character written, or
+ NULL if the escape character is not supported. */
+
+static unsigned char *
+handle_escape_character (unsigned char *buffer, char c)
+{
+ switch (c)
+ {
+ case '"':
+ *buffer++ = '"';
+ *buffer++ = '"';
+ break;
+
+ case 'n':
+ strcpy ((char *) buffer, "\" & ASCII.LF & \"");
+ buffer += 16;
+ break;
+
+ case 'r':
+ strcpy ((char *) buffer, "\" & ASCII.CR & \"");
+ buffer += 16;
+ break;
+
+ case 't':
+ strcpy ((char *) buffer, "\" & ASCII.HT & \"");
+ buffer += 16;
+ break;
+
+ default:
+ return NULL;
+ }
+
+ return buffer;
+}
+
/* Dump into PP a set of MAX_ADA_MACROS MACROS (C/C++) as Ada constants when
possible. */
@@ -132,7 +184,7 @@ print_ada_macros (pretty_printer *pp, cpp_hashnode **macros, int max_ada_macros)
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;
+ unsigned char *s, *params, *buffer, *buf_param, *char_one = NULL, *tmp;
macro_length (macro, &supported, &buffer_len, &param_len);
s = buffer = XALLOCAVEC (unsigned char, buffer_len);
@@ -246,14 +298,33 @@ print_ada_macros (pretty_printer *pp, cpp_hashnode **macros, int max_ada_macros)
case CPP_CHAR32:
case CPP_UTF8CHAR:
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_STRING:
+ is_string = 1;
+ {
+ const unsigned char *s = token->val.str.text;
+
+ for (; *s; s++)
+ if (*s == '\\')
+ {
+ s++;
+ buffer = handle_escape_character (buffer, *s);
+ if (buffer == NULL)
+ {
+ supported = 0;
+ break;
+ }
+ }
+ else
+ *buffer++ = *s;
+ }
+ break;
+
case CPP_CHAR:
is_char = 1;
{
@@ -278,6 +349,72 @@ print_ada_macros (pretty_printer *pp, cpp_hashnode **macros, int max_ada_macros)
}
break;
+ case CPP_NUMBER:
+ tmp = cpp_token_as_text (parse_in, token);
+
+ switch (*tmp)
+ {
+ case '0':
+ switch (tmp[1])
+ {
+ case '\0':
+ case 'l':
+ case 'L':
+ case 'u':
+ case 'U':
+ *buffer++ = '0';
+ break;
+
+ case 'x':
+ case 'X':
+ *buffer++ = '1';
+ *buffer++ = '6';
+ *buffer++ = '#';
+ buffer = dump_number (tmp + 2, buffer);
+ *buffer++ = '#';
+ break;
+
+ case 'b':
+ case 'B':
+ *buffer++ = '2';
+ *buffer++ = '#';
+ buffer = dump_number (tmp + 2, buffer);
+ *buffer++ = '#';
+ break;
+
+ default:
+ /* Dump floating constants unmodified. */
+ if (strchr ((const char *)tmp, '.'))
+ buffer = dump_number (tmp, buffer);
+ else
+ {
+ *buffer++ = '8';
+ *buffer++ = '#';
+ buffer = dump_number (tmp + 1, buffer);
+ *buffer++ = '#';
+ }
+ break;
+ }
+ break;
+
+ case '1':
+ if (tmp[1] == '\0' || tmp[1] == 'l' || tmp[1] == 'u'
+ || tmp[1] == 'L' || tmp[1] == 'U')
+ {
+ is_one = 1;
+ char_one = buffer;
+ *buffer++ = '1';
+ }
+ else
+ buffer = dump_number (tmp, buffer);
+ break;
+
+ default:
+ buffer = dump_number (tmp, buffer);
+ break;
+ }
+ break;
+
case CPP_LSHIFT:
if (prev_is_one)
{
@@ -892,25 +1029,22 @@ static const char *c_duplicates[] = {
static tree
get_underlying_decl (tree type)
{
- tree decl = NULL_TREE;
-
- if (type == NULL_TREE)
+ if (!type)
return NULL_TREE;
/* type is a declaration. */
if (DECL_P (type))
- decl = type;
+ return type;
/* type is a typedef. */
if (TYPE_P (type) && TYPE_NAME (type) && DECL_P (TYPE_NAME (type)))
- decl = TYPE_NAME (type);
+ return 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);
+ if (TYPE_P (type) && TYPE_STUB_DECL (type))
+ return TYPE_STUB_DECL (type);
- return decl;
+ return NULL_TREE;
}
/* Return whether TYPE has static fields. */
@@ -1469,7 +1603,7 @@ dump_ada_function_declaration (pretty_printer *buffer, tree func,
{
tree arg;
const tree node = TREE_TYPE (func);
- char buf[16];
+ char buf[17];
int num = 0, num_args = 0, have_args = true, have_ellipsis = false;
/* Compute number of arguments. */
@@ -1549,13 +1683,18 @@ dump_ada_function_declaration (pretty_printer *buffer, tree func,
dump_generic_ada_node (buffer, TREE_VALUE (arg), node, 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");
- }
+ /* If the type is a pointer to a tagged type, we need to differentiate
+ virtual methods from the rest (non-virtual methods, static member
+ or regular functions) and import only them as primitive operations,
+ because they make up the virtual table which is mirrored on the Ada
+ side by the dispatch table. So we add 'Class to the type of every
+ parameter that is not the first one of a method which either has a
+ slot in the virtual table or is a constructor. */
+ if (TREE_TYPE (arg)
+ && POINTER_TYPE_P (TREE_TYPE (arg))
+ && is_tagged_type (TREE_TYPE (TREE_TYPE (arg)))
+ && !(num == 1 && is_method && (DECL_VINDEX (func) || is_constructor)))
+ pp_string (buffer, "'Class");
arg = TREE_CHAIN (arg);
@@ -1865,6 +2004,7 @@ dump_generic_ada_node (pretty_printer *buffer, tree node, tree type, int spc,
case TREE_BINFO:
dump_generic_ada_node
(buffer, BINFO_TYPE (node), type, spc, limited_access, name_only);
+ return 0;
case TREE_VEC:
pp_string (buffer, "--- unexpected node: TREE_VEC");
@@ -2083,37 +2223,25 @@ dump_generic_ada_node (pretty_printer *buffer, tree node, tree type, int spc,
}
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));
+ tree decl = get_underlying_decl (TREE_TYPE (node));
+ tree enclosing_decl = get_underlying_decl (type);
+ /* For now, handle access-to-access, access-to-empty-struct
+ or access-to-incomplete as opaque system.address. */
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)))
+ && !TYPE_FIELDS (TREE_TYPE (node)))
+ || !decl
+ || (!enclosing_decl
+ && !TREE_VISITED (decl)
+ && DECL_SOURCE_FILE (decl) == source_file_base)
+ || (enclosing_decl
+ && !TREE_VISITED (decl)
+ && DECL_SOURCE_FILE (decl)
+ == DECL_SOURCE_FILE (enclosing_decl)
+ && decl_sloc (decl, true)
+ > decl_sloc (enclosing_decl, true)))
{
if (package_prefix)
{
@@ -2160,13 +2288,11 @@ dump_generic_ada_node (pretty_printer *buffer, tree node, tree type, int spc,
}
if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (node)) && type_name)
- dump_generic_ada_node
- (buffer, type_name,
- TREE_TYPE (node), spc, is_access, true);
+ dump_generic_ada_node (buffer, type_name, TREE_TYPE (node),
+ spc, is_access, true);
else
- dump_generic_ada_node
- (buffer, TREE_TYPE (node), TREE_TYPE (node),
- spc, 0, true);
+ dump_generic_ada_node (buffer, TREE_TYPE (node),
+ TREE_TYPE (node), spc, 0, true);
}
}
}
@@ -2311,25 +2437,11 @@ dump_generic_ada_node (pretty_printer *buffer, tree node, tree type, int spc,
}
/* Dump in BUFFER NODE's methods. SPC is the indentation level. Return 1 if
- methods were printed, 0 otherwise.
-
- We do it in 2 passes: first, the regular methods, i.e. non-static member
- functions, are output immediately within the package created for the class
- so that they are considered as primitive operations in Ada; second, the
- static member functions are output in a nested package so that they are
- _not_ considered as primitive operations in Ada.
-
- This approach is necessary because the formers have the implicit 'this'
- pointer whereas the latters don't and, on 32-bit x86/Windows, the calling
- conventions for the 'this' pointer are special. Therefore, the compiler
- needs to be able to differentiate regular methods (with 'this' pointer)
- from static member functions that take a pointer to the class as first
- parameter. */
+ methods were printed, 0 otherwise. */
static int
print_ada_methods (pretty_printer *buffer, tree node, int spc)
{
- bool has_static_methods = false;
tree t;
int res;
@@ -2338,42 +2450,9 @@ print_ada_methods (pretty_printer *buffer, tree node, int spc)
pp_semicolon (buffer);
- /* First pass: the regular methods. */
res = 1;
for (t = TYPE_METHODS (node); t; t = TREE_CHAIN (t))
{
- if (TREE_CODE (TREE_TYPE (t)) != METHOD_TYPE)
- {
- has_static_methods = true;
- continue;
- }
-
- if (res)
- {
- pp_newline (buffer);
- pp_newline (buffer);
- }
-
- res = print_ada_declaration (buffer, t, node, spc);
- }
-
- if (!has_static_methods)
- return 1;
-
- pp_newline (buffer);
- newline_and_indent (buffer, spc);
-
- /* Second pass: the static member functions. */
- pp_string (buffer, "package Static is");
- pp_newline (buffer);
- spc += INDENT_INCR;
-
- res = 0;
- for (t = TYPE_METHODS (node); t; t = TREE_CHAIN (t))
- {
- if (TREE_CODE (TREE_TYPE (t)) == METHOD_TYPE)
- continue;
-
if (res)
{
pp_newline (buffer);
@@ -2383,49 +2462,6 @@ print_ada_methods (pretty_printer *buffer, tree node, int spc)
res = print_ada_declaration (buffer, t, node, spc);
}
- spc -= INDENT_INCR;
- newline_and_indent (buffer, spc);
- pp_string (buffer, "end;");
-
- /* In order to save the clients from adding a second use clause for the
- nested package, we generate renamings for the static member functions
- in the package created for the class. */
- for (t = TYPE_METHODS (node); t; t = TREE_CHAIN (t))
- {
- bool is_function;
-
- if (TREE_CODE (TREE_TYPE (t)) == METHOD_TYPE)
- continue;
-
- pp_newline (buffer);
- newline_and_indent (buffer, spc);
-
- if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (t))))
- {
- pp_string (buffer, "procedure ");
- is_function = false;
- }
- else
- {
- pp_string (buffer, "function ");
- is_function = true;
- }
-
- dump_ada_decl_name (buffer, t, false);
- dump_ada_function_declaration (buffer, t, false, false, false, spc);
-
- if (is_function)
- {
- pp_string (buffer, " return ");
- dump_generic_ada_node (buffer, TREE_TYPE (TREE_TYPE (t)), node,
- spc, false, true);
- }
-
- pp_string (buffer, " renames Static.");
- dump_ada_decl_name (buffer, t, false);
- pp_semicolon (buffer);
- }
-
return 1;
}
@@ -2507,13 +2543,12 @@ dump_nested_type (pretty_printer *buffer, tree field, tree t, tree parent,
decl = get_underlying_decl (tmp);
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))))
+ || TYPE_FIELDS (TREE_TYPE (decl)))
+ && !TREE_VISITED (decl)
+ && DECL_SOURCE_FILE (decl) == DECL_SOURCE_FILE (t)
+ && decl_sloc (decl, true) > decl_sloc (t, true))
{
/* Generate forward declaration. */
pp_string (buffer, "type ");
@@ -2529,10 +2564,7 @@ dump_nested_type (pretty_printer *buffer, tree field, tree t, tree parent,
while (TREE_CODE (tmp) == ARRAY_TYPE)
tmp = TREE_TYPE (tmp);
decl = get_underlying_decl (tmp);
- if (decl
- && DECL_P (decl)
- && !DECL_NAME (decl)
- && !TREE_VISITED (decl))
+ if (decl && !DECL_NAME (decl) && !TREE_VISITED (decl))
{
/* Generate full declaration. */
dump_nested_type (buffer, decl, t, parent, spc);
@@ -2682,7 +2714,10 @@ print_ada_declaration (pretty_printer *buffer, tree t, tree type, int spc)
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;
+ {
+ TREE_VISITED (t) = 1;
+ return 0;
+ }
INDENT (spc);
@@ -2693,7 +2728,7 @@ print_ada_declaration (pretty_printer *buffer, tree t, tree type, int spc)
}
else
{
- if (!TREE_VISITED (stub)
+ if (RECORD_OR_UNION_TYPE_P (typ)
&& DECL_SOURCE_FILE (stub) == source_file_base)
dump_nested_types (buffer, stub, stub, true, spc);
@@ -2701,8 +2736,11 @@ print_ada_declaration (pretty_printer *buffer, tree t, tree type, int spc)
dump_generic_ada_node (buffer, t, type, spc, false, true);
pp_string (buffer, " is ");
dump_generic_ada_node (buffer, typ, type, spc, false, true);
- pp_semicolon (buffer);
+ pp_string (buffer, "; -- ");
+ dump_sloc (buffer, t);
}
+
+ TREE_VISITED (t) = 1;
return 1;
}
}
@@ -2780,7 +2818,6 @@ print_ada_declaration (pretty_printer *buffer, tree t, tree type, int spc)
pp_string (buffer, "-- skipped function type ");
dump_generic_ada_node (buffer, t, type, spc, false, true);
return 1;
- break;
case ENUMERAL_TYPE:
if ((orig && TYPE_NAME (orig) && orig != TREE_TYPE (t))
diff --git a/gcc/c-family/c-ada-spec.h b/gcc/c-family/c-ada-spec.h
index 8be94f001b..b1e1d0d269 100644
--- a/gcc/c-family/c-ada-spec.h
+++ b/gcc/c-family/c-ada-spec.h
@@ -1,5 +1,5 @@
/* Interface for -fdump-ada-spec capability.
- Copyright (C) 2010-2016 Free Software Foundation, Inc.
+ Copyright (C) 2010-2017 Free Software Foundation, Inc.
This file is part of GCC.
diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
new file mode 100644
index 0000000000..f2a88e147b
--- /dev/null
+++ b/gcc/c-family/c-attribs.c
@@ -0,0 +1,3175 @@
+/* C-family attributes handling.
+ Copyright (C) 1992-2017 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 "target.h"
+#include "function.h"
+#include "tree.h"
+#include "memmodel.h"
+#include "c-common.h"
+#include "gimple-expr.h"
+#include "tm_p.h"
+#include "stringpool.h"
+#include "cgraph.h"
+#include "diagnostic.h"
+#include "intl.h"
+#include "stor-layout.h"
+#include "calls.h"
+#include "attribs.h"
+#include "varasm.h"
+#include "trans-mem.h"
+#include "c-objc.h"
+#include "common/common-target.h"
+#include "langhooks.h"
+#include "tree-inline.h"
+#include "toplev.h"
+#include "tree-iterator.h"
+#include "opts.h"
+#include "gimplify.h"
+
+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_no_sanitize_address_attribute (tree *, tree, tree,
+ int, bool *);
+static tree handle_no_address_safety_analysis_attribute (tree *, tree, tree,
+ int, bool *);
+static tree handle_no_sanitize_undefined_attribute (tree *, tree, tree, int,
+ bool *);
+static tree handle_asan_odr_indicator_attribute (tree *, tree, tree, int,
+ bool *);
+static tree handle_stack_protect_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_noicf_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_externally_visible_attribute (tree *, tree, tree, int,
+ bool *);
+static tree handle_no_reorder_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_scalar_storage_order_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_noplt_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_no_profile_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_tm_attribute (tree *, tree, tree, int, bool *);
+static tree handle_tm_wrap_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_alloc_align_attribute (tree *, tree, tree, int, bool *);
+static tree handle_assume_aligned_attribute (tree *, tree, tree, int, bool *);
+static tree handle_target_attribute (tree *, tree, tree, int, bool *);
+static tree handle_target_clones_attribute (tree *, tree, tree, int, bool *);
+static tree handle_optimize_attribute (tree *, tree, tree, int, bool *);
+static tree ignore_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 tree handle_warn_unused_attribute (tree *, tree, tree, int, bool *);
+static tree handle_returns_nonnull_attribute (tree *, tree, tree, int, bool *);
+static tree handle_omp_declare_simd_attribute (tree *, tree, tree, int,
+ bool *);
+static tree handle_simd_attribute (tree *, tree, tree, int, bool *);
+static tree handle_omp_declare_target_attribute (tree *, tree, tree, int,
+ bool *);
+static tree handle_designated_init_attribute (tree *, tree, tree, int, bool *);
+static tree handle_bnd_variable_size_attribute (tree *, tree, tree, int, bool *);
+static tree handle_bnd_legacy (tree *, tree, tree, int, bool *);
+static tree handle_bnd_instrument (tree *, tree, tree, int, bool *);
+static tree handle_fallthrough_attribute (tree *, tree, tree, int, bool *);
+
+/* Table of machine-independent attributes common to all C-like languages.
+
+ All attributes referencing arguments should be additionally processed
+ in chkp_copy_function_type_adding_bounds for correct instrumentation
+ by Pointer Bounds Checker.
+ Current list of processed common attributes: nonnull. */
+const struct attribute_spec c_common_attribute_table[] =
+{
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
+ affects_type_identity } */
+ { "packed", 0, 0, false, false, false,
+ handle_packed_attribute , false},
+ { "nocommon", 0, 0, true, false, false,
+ handle_nocommon_attribute, false},
+ { "common", 0, 0, true, false, false,
+ handle_common_attribute, false },
+ /* 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, false },
+ { "volatile", 0, 0, true, false, false,
+ handle_noreturn_attribute, false },
+ { "stack_protect", 0, 0, true, false, false,
+ handle_stack_protect_attribute, false },
+ { "noinline", 0, 0, true, false, false,
+ handle_noinline_attribute, false },
+ { "noclone", 0, 0, true, false, false,
+ handle_noclone_attribute, false },
+ { "no_icf", 0, 0, true, false, false,
+ handle_noicf_attribute, false },
+ { "leaf", 0, 0, true, false, false,
+ handle_leaf_attribute, false },
+ { "always_inline", 0, 0, true, false, false,
+ handle_always_inline_attribute, false },
+ { "gnu_inline", 0, 0, true, false, false,
+ handle_gnu_inline_attribute, false },
+ { "artificial", 0, 0, true, false, false,
+ handle_artificial_attribute, false },
+ { "flatten", 0, 0, true, false, false,
+ handle_flatten_attribute, false },
+ { "used", 0, 0, true, false, false,
+ handle_used_attribute, false },
+ { "unused", 0, 0, false, false, false,
+ handle_unused_attribute, false },
+ { "externally_visible", 0, 0, true, false, false,
+ handle_externally_visible_attribute, false },
+ { "no_reorder", 0, 0, true, false, false,
+ handle_no_reorder_attribute, false },
+ /* The same comments as for noreturn attributes apply to const ones. */
+ { "const", 0, 0, true, false, false,
+ handle_const_attribute, false },
+ { "scalar_storage_order", 1, 1, false, false, false,
+ handle_scalar_storage_order_attribute, false },
+ { "transparent_union", 0, 0, false, false, false,
+ handle_transparent_union_attribute, false },
+ { "constructor", 0, 1, true, false, false,
+ handle_constructor_attribute, false },
+ { "destructor", 0, 1, true, false, false,
+ handle_destructor_attribute, false },
+ { "mode", 1, 1, false, true, false,
+ handle_mode_attribute, false },
+ { "section", 1, 1, true, false, false,
+ handle_section_attribute, false },
+ { "aligned", 0, 1, false, false, false,
+ handle_aligned_attribute, false },
+ { "weak", 0, 0, true, false, false,
+ handle_weak_attribute, false },
+ { "noplt", 0, 0, true, false, false,
+ handle_noplt_attribute, false },
+ { "ifunc", 1, 1, true, false, false,
+ handle_ifunc_attribute, false },
+ { "alias", 1, 1, true, false, false,
+ handle_alias_attribute, false },
+ { "weakref", 0, 1, true, false, false,
+ handle_weakref_attribute, false },
+ { "no_instrument_function", 0, 0, true, false, false,
+ handle_no_instrument_function_attribute,
+ false },
+ { "no_profile_instrument_function", 0, 0, true, false, false,
+ handle_no_profile_instrument_function_attribute,
+ false },
+ { "malloc", 0, 0, true, false, false,
+ handle_malloc_attribute, false },
+ { "returns_twice", 0, 0, true, false, false,
+ handle_returns_twice_attribute, false },
+ { "no_stack_limit", 0, 0, true, false, false,
+ handle_no_limit_stack_attribute, false },
+ { "pure", 0, 0, true, false, false,
+ handle_pure_attribute, false },
+ { "transaction_callable", 0, 0, false, true, false,
+ handle_tm_attribute, false },
+ { "transaction_unsafe", 0, 0, false, true, false,
+ handle_tm_attribute, true },
+ { "transaction_safe", 0, 0, false, true, false,
+ handle_tm_attribute, true },
+ { "transaction_safe_dynamic", 0, 0, true, false, false,
+ handle_tm_attribute, false },
+ { "transaction_may_cancel_outer", 0, 0, false, true, false,
+ handle_tm_attribute, false },
+ /* ??? These two attributes didn't make the transition from the
+ Intel language document to the multi-vendor language document. */
+ { "transaction_pure", 0, 0, false, true, false,
+ handle_tm_attribute, false },
+ { "transaction_wrap", 1, 1, true, false, false,
+ handle_tm_wrap_attribute, false },
+ /* 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, false },
+ { "deprecated", 0, 1, false, false, false,
+ handle_deprecated_attribute, false },
+ { "vector_size", 1, 1, false, true, false,
+ handle_vector_size_attribute, true },
+ { "visibility", 1, 1, false, false, false,
+ handle_visibility_attribute, false },
+ { "tls_model", 1, 1, true, false, false,
+ handle_tls_model_attribute, false },
+ { "nonnull", 0, -1, false, true, true,
+ handle_nonnull_attribute, false },
+ { "nothrow", 0, 0, true, false, false,
+ handle_nothrow_attribute, false },
+ { "may_alias", 0, 0, false, true, false, NULL, false },
+ { "cleanup", 1, 1, true, false, false,
+ handle_cleanup_attribute, false },
+ { "warn_unused_result", 0, 0, false, true, true,
+ handle_warn_unused_result_attribute, false },
+ { "sentinel", 0, 1, false, true, true,
+ handle_sentinel_attribute, false },
+ /* 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, false },
+ { "alloc_size", 1, 2, false, true, true,
+ handle_alloc_size_attribute, false },
+ { "cold", 0, 0, true, false, false,
+ handle_cold_attribute, false },
+ { "hot", 0, 0, true, false, false,
+ handle_hot_attribute, false },
+ { "no_address_safety_analysis",
+ 0, 0, true, false, false,
+ handle_no_address_safety_analysis_attribute,
+ false },
+ { "no_sanitize_address", 0, 0, true, false, false,
+ handle_no_sanitize_address_attribute,
+ false },
+ { "no_sanitize_thread", 0, 0, true, false, false,
+ handle_no_sanitize_address_attribute,
+ false },
+ { "no_sanitize_undefined", 0, 0, true, false, false,
+ handle_no_sanitize_undefined_attribute,
+ false },
+ { "asan odr indicator", 0, 0, true, false, false,
+ handle_asan_odr_indicator_attribute,
+ false },
+ { "warning", 1, 1, true, false, false,
+ handle_error_attribute, false },
+ { "error", 1, 1, true, false, false,
+ handle_error_attribute, false },
+ { "target", 1, -1, true, false, false,
+ handle_target_attribute, false },
+ { "target_clones", 1, -1, true, false, false,
+ handle_target_clones_attribute, false },
+ { "optimize", 1, -1, true, false, false,
+ handle_optimize_attribute, false },
+ /* For internal use only. The leading '*' both prevents its usage in
+ source code and signals that it may be overridden by machine tables. */
+ { "*tm regparm", 0, 0, false, true, true,
+ ignore_attribute, false },
+ { "no_split_stack", 0, 0, true, false, false,
+ handle_no_split_stack_attribute, false },
+ /* 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, false },
+ { "warn_unused", 0, 0, false, false, false,
+ handle_warn_unused_attribute, false },
+ { "returns_nonnull", 0, 0, false, true, true,
+ handle_returns_nonnull_attribute, false },
+ { "omp declare simd", 0, -1, true, false, false,
+ handle_omp_declare_simd_attribute, false },
+ { "cilk simd function", 0, -1, true, false, false,
+ handle_omp_declare_simd_attribute, false },
+ { "simd", 0, 1, true, false, false,
+ handle_simd_attribute, false },
+ { "omp declare target", 0, 0, true, false, false,
+ handle_omp_declare_target_attribute, false },
+ { "omp declare target link", 0, 0, true, false, false,
+ handle_omp_declare_target_attribute, false },
+ { "alloc_align", 1, 1, false, true, true,
+ handle_alloc_align_attribute, false },
+ { "assume_aligned", 1, 2, false, true, true,
+ handle_assume_aligned_attribute, false },
+ { "designated_init", 0, 0, false, true, false,
+ handle_designated_init_attribute, false },
+ { "bnd_variable_size", 0, 0, true, false, false,
+ handle_bnd_variable_size_attribute, false },
+ { "bnd_legacy", 0, 0, true, false, false,
+ handle_bnd_legacy, false },
+ { "bnd_instrument", 0, 0, true, false, false,
+ handle_bnd_instrument, false },
+ { "fallthrough", 0, 0, false, false, false,
+ handle_fallthrough_attribute, false },
+ { NULL, 0, 0, false, false, false, NULL, false }
+};
+
+/* Give the specifications for the format attributes, used by C and all
+ descendants.
+
+ All attributes referencing arguments should be additionally processed
+ in chkp_copy_function_type_adding_bounds for correct instrumentation
+ by Pointer Bounds Checker.
+ Current list of processed format attributes: format, format_arg. */
+const struct attribute_spec c_common_format_attribute_table[] =
+{
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
+ affects_type_identity } */
+ { "format", 3, 3, false, true, true,
+ handle_format_attribute, false },
+ { "format_arg", 1, 1, false, true, true,
+ handle_format_arg_attribute, false },
+ { NULL, 0, 0, false, false, false, NULL, false }
+};
+
+/* 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 (VAR_P (*node))
+ 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 (VAR_P (*node))
+ 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_qualified_type
+ (build_pointer_type
+ (build_type_variant (TREE_TYPE (type),
+ TYPE_READONLY (TREE_TYPE (type)), 1)),
+ TYPE_QUALS (type)));
+ 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
+ || TREE_CODE (*node) == LABEL_DECL)
+ {
+ if (lookup_attribute ("cold", DECL_ATTRIBUTES (*node)) != NULL)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
+ "with attribute %qs", 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
+ || TREE_CODE (*node) == LABEL_DECL)
+ {
+ if (lookup_attribute ("hot", DECL_ATTRIBUTES (*node)) != NULL)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
+ "with attribute %qs", 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 "no_sanitize_address" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_no_sanitize_address_attribute (tree *node, tree name, tree, int,
+ 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 "no_address_safety_analysis" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_no_address_safety_analysis_attribute (tree *node, tree name, tree, int,
+ bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ else if (!lookup_attribute ("no_sanitize_address", DECL_ATTRIBUTES (*node)))
+ DECL_ATTRIBUTES (*node)
+ = tree_cons (get_identifier ("no_sanitize_address"),
+ NULL_TREE, DECL_ATTRIBUTES (*node));
+ *no_add_attrs = true;
+ return NULL_TREE;
+}
+
+/* Handle a "no_sanitize_undefined" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_no_sanitize_undefined_attribute (tree *node, tree name, tree, int,
+ 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 an "asan odr indicator" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_asan_odr_indicator_attribute (tree *, tree, tree, int, bool *)
+{
+ return NULL_TREE;
+}
+
+/* Handle a "stack_protect" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_stack_protect_attribute (tree *node, tree name, tree, int,
+ bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+ else
+ DECL_ATTRIBUTES (*node)
+ = tree_cons (get_identifier ("stack_protect"),
+ NULL_TREE, DECL_ATTRIBUTES (*node));
+
+ 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)
+ {
+ if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (*node)))
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
+ "with attribute %qs", name, "always_inline");
+ *no_add_attrs = true;
+ }
+ else
+ 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 "no_icf" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_noicf_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)
+ {
+ if (lookup_attribute ("noinline", DECL_ATTRIBUTES (*node)))
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
+ "with %qs attribute", name, "noinline");
+ *no_add_attrs = true;
+ }
+ else if (lookup_attribute ("target_clones", DECL_ATTRIBUTES (*node)))
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
+ "with %qs attribute", name, "target_clones");
+ *no_add_attrs = true;
+ }
+ else
+ /* 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
+ || (VAR_P (node) && TREE_STATIC (node))
+ || (TREE_CODE (node) == TYPE_DECL))
+ {
+ TREE_USED (node) = 1;
+ DECL_PRESERVE_P (node) = 1;
+ if (VAR_P (node))
+ 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. */
+
+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
+ || VAR_OR_FUNCTION_DECL_P (decl)
+ || TREE_CODE (decl) == LABEL_DECL
+ || TREE_CODE (decl) == CONST_DECL
+ || TREE_CODE (decl) == TYPE_DECL)
+ {
+ TREE_USED (decl) = 1;
+ if (VAR_P (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 (VAR_OR_FUNCTION_DECL_P (node))
+ {
+ 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 the "no_reorder" attribute. Arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_no_reorder_attribute (tree *pnode,
+ tree name,
+ tree,
+ int,
+ bool *no_add_attrs)
+{
+ tree node = *pnode;
+
+ if (!VAR_OR_FUNCTION_DECL_P (node)
+ && !(TREE_STATIC (node) || DECL_EXTERNAL (node)))
+ {
+ warning (OPT_Wattributes,
+ "%qE attribute only affects top level objects",
+ 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_qualified_type
+ (build_pointer_type
+ (build_type_variant (TREE_TYPE (type), 1,
+ TREE_THIS_VOLATILE (TREE_TYPE (type)))),
+ TYPE_QUALS (type)));
+ else
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "scalar_storage_order" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_scalar_storage_order_attribute (tree *node, tree name, tree args,
+ int flags, bool *no_add_attrs)
+{
+ tree id = TREE_VALUE (args);
+ tree type;
+
+ if (TREE_CODE (*node) == TYPE_DECL
+ && ! (flags & ATTR_FLAG_CXX11))
+ node = &TREE_TYPE (*node);
+ type = *node;
+
+ if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN)
+ {
+ error ("scalar_storage_order is not supported because endianness "
+ "is not uniform");
+ return NULL_TREE;
+ }
+
+ if (RECORD_OR_UNION_TYPE_P (type) && !c_dialect_cxx ())
+ {
+ bool reverse = false;
+
+ if (TREE_CODE (id) == STRING_CST
+ && strcmp (TREE_STRING_POINTER (id), "big-endian") == 0)
+ reverse = !BYTES_BIG_ENDIAN;
+ else if (TREE_CODE (id) == STRING_CST
+ && strcmp (TREE_STRING_POINTER (id), "little-endian") == 0)
+ reverse = BYTES_BIG_ENDIAN;
+ else
+ {
+ error ("scalar_storage_order argument must be one of \"big-endian\""
+ " or \"little-endian\"");
+ return NULL_TREE;
+ }
+
+ if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
+ {
+ if (reverse)
+ /* A type variant isn't good enough, since we don't want a cast
+ to such a type to be removed as a no-op. */
+ *node = type = build_duplicate_type (type);
+ }
+
+ TYPE_REVERSE_STORAGE_ORDER (type) = reverse;
+ return NULL_TREE;
+ }
+
+ 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
+ && ! (flags & ATTR_FLAG_CXX11))
+ node = &TREE_TYPE (*node);
+ type = *node;
+
+ if (TREE_CODE (type) == UNION_TYPE)
+ {
+ /* Make sure that the first field will work for a transparent union.
+ If the type isn't complete yet, leave the check to the code in
+ finish_struct. */
+ if (TYPE_SIZE (type))
+ {
+ tree first = first_field (type);
+ if (first == NULL_TREE
+ || DECL_ARTIFICIAL (first)
+ || TYPE_MODE (type) != DECL_MODE (first))
+ goto ignored;
+ }
+
+ if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
+ {
+ /* If the type isn't complete yet, setting the flag
+ on a variant wouldn't ever be checked. */
+ if (!TYPE_SIZE (type))
+ goto ignored;
+
+ /* build_duplicate_type doesn't work for C++. */
+ if (c_dialect_cxx ())
+ goto ignored;
+
+ /* A type variant isn't good enough, since we don't want a cast
+ to such a type to be removed as a no-op. */
+ *node = type = build_duplicate_type (type);
+ }
+
+ for (tree t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
+ TYPE_TRANSPARENT_AGGR (t) = 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 (TREE_CODE (arg) == IDENTIFIER_NODE)
+ goto invalid;
+ if (arg == error_mark_node)
+ return DEFAULT_INIT_PRIORITY;
+ arg = default_conversion (arg);
+ if (!tree_fits_shwi_p (arg)
+ || !INTEGRAL_TYPE_P (TREE_TYPE (arg)))
+ goto invalid;
+
+ pri = tree_to_shwi (arg);
+ 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 bool
+vector_mode_valid_p (machine_mode mode)
+{
+ enum mode_class mclass = GET_MODE_CLASS (mode);
+ 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 false;
+
+ /* Hardware support. Woo hoo! */
+ if (targetm.vector_mode_supported_p (mode))
+ return true;
+
+ 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);
+ 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 = (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, 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 = build_qualified_type (typefm, TYPE_QUALS (type));
+ }
+
+ 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_common.have_named_sections)
+ {
+ error_at (DECL_SOURCE_LOCATION (*node),
+ "section attributes are not supported for this target");
+ goto fail;
+ }
+
+ if (!VAR_OR_FUNCTION_DECL_P (decl))
+ {
+ error ("section attribute not allowed for %q+D", *node);
+ goto fail;
+ }
+
+ if (TREE_CODE (TREE_VALUE (args)) != STRING_CST)
+ {
+ error ("section attribute argument not a string constant");
+ goto fail;
+ }
+
+ if (VAR_P (decl)
+ && current_function_decl != NULL_TREE
+ && !TREE_STATIC (decl))
+ {
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "section attribute cannot be specified for local variables");
+ goto fail;
+ }
+
+ /* The decl may have already been given a section attribute
+ from a previous declaration. Ensure they match. */
+ if (DECL_SECTION_NAME (decl) != NULL
+ && strcmp (DECL_SECTION_NAME (decl),
+ TREE_STRING_POINTER (TREE_VALUE (args))) != 0)
+ {
+ error ("section of %q+D conflicts with previous declaration", *node);
+ goto fail;
+ }
+
+ if (VAR_P (decl)
+ && !targetm.have_tls && targetm.emutls.tmpl_section
+ && DECL_THREAD_LOCAL_P (decl))
+ {
+ error ("section of %q+D cannot be overridden", *node);
+ goto fail;
+ }
+
+ set_decl_section_name (decl, TREE_STRING_POINTER (TREE_VALUE (args)));
+ return NULL_TREE;
+
+fail:
+ *no_add_attrs = true;
+ return NULL_TREE;
+}
+
+/* If in c++-11, check if the c++-11 alignment constraint with respect
+ to fundamental alignment (in [dcl.align]) are satisfied. If not in
+ c++-11 mode, does nothing.
+
+ [dcl.align]2/ says:
+
+ [* if the constant expression evaluates to a fundamental alignment,
+ the alignment requirement of the declared entity shall be the
+ specified fundamental alignment.
+
+ * if the constant expression evaluates to an extended alignment
+ and the implementation supports that alignment in the context
+ of the declaration, the alignment of the declared entity shall
+ be that alignment
+
+ * if the constant expression evaluates to an extended alignment
+ and the implementation does not support that alignment in the
+ context of the declaration, the program is ill-formed]. */
+
+static bool
+check_cxx_fundamental_alignment_constraints (tree node,
+ unsigned align_log,
+ int flags)
+{
+ bool alignment_too_large_p = false;
+ unsigned requested_alignment = (1U << align_log) * BITS_PER_UNIT;
+ unsigned max_align = 0;
+
+ if ((!(flags & ATTR_FLAG_CXX11) && !warn_cxx_compat)
+ || (node == NULL_TREE || node == error_mark_node))
+ return true;
+
+ if (cxx_fundamental_alignment_p (requested_alignment))
+ return true;
+
+ if (VAR_P (node))
+ {
+ if (TREE_STATIC (node) || DECL_EXTERNAL (node))
+ /* For file scope variables and static members, the target supports
+ alignments that are at most MAX_OFILE_ALIGNMENT. */
+ max_align = MAX_OFILE_ALIGNMENT;
+ else
+ /* For stack variables, the target supports at most
+ MAX_STACK_ALIGNMENT. */
+ max_align = MAX_STACK_ALIGNMENT;
+ if (requested_alignment > max_align)
+ alignment_too_large_p = true;
+ }
+ /* Let's be liberal for types and fields; don't limit their alignment any
+ more than check_user_alignment already did. */
+
+ if (alignment_too_large_p)
+ pedwarn (input_location, OPT_Wattributes,
+ "requested alignment %d is larger than %d",
+ requested_alignment / BITS_PER_UNIT, max_align / BITS_PER_UNIT);
+
+ return !alignment_too_large_p;
+}
+
+/* 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;
+ int i;
+
+ if (args)
+ {
+ align_expr = TREE_VALUE (args);
+ if (align_expr && TREE_CODE (align_expr) != IDENTIFIER_NODE
+ && TREE_CODE (align_expr) != FUNCTION_DECL)
+ align_expr = default_conversion (align_expr);
+ }
+ else
+ align_expr = size_int (ATTRIBUTE_ALIGNED_VALUE / BITS_PER_UNIT);
+
+ 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 ((i = check_user_alignment (align_expr, true)) == -1
+ || !check_cxx_fundamental_alignment_constraints (*node, i, flags))
+ *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);
+
+ SET_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 (DECL_USER_ALIGN (decl)
+ && DECL_ALIGN (decl) > (1U << i) * BITS_PER_UNIT)
+ /* C++-11 [dcl.align/4]:
+
+ When multiple alignment-specifiers are specified for an
+ entity, the alignment requirement shall be set to the
+ strictest specified alignment.
+
+ This formally comes from the c++11 specification but we are
+ doing it for the GNU attribute syntax as well. */
+ *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
+ {
+ SET_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 (VAR_OR_FUNCTION_DECL_P (*node))
+ declare_weak (*node);
+ else
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+
+ return NULL_TREE;
+}
+
+/* Handle a "noplt" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_noplt_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)
+ {
+ warning (OPT_Wattributes,
+ "%qE attribute is only applicable on functions", name);
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+ 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 || !VAR_P (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
+ 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;
+ }
+
+ if (decl_in_symtab_p (*node))
+ {
+ struct symtab_node *n = symtab_node::get (decl);
+ if (n && n->refuse_visibility_changes)
+ {
+ if (is_alias)
+ error ("%+D declared alias after being used", decl);
+ else
+ error ("%+D declared ifunc after being used", decl);
+ }
+ }
+
+
+ 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
+ || !VAR_OR_FUNCTION_DECL_P (*node))
+ {
+ 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;
+ }
+
+ if (decl_in_symtab_p (*node))
+ {
+ struct symtab_node *n = symtab_node::get (*node);
+ if (n && n->refuse_visibility_changes)
+ error ("%+D declared weakref after being used", *node);
+ }
+
+ 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 (!RECORD_OR_UNION_TYPE_P (*node))
+ {
+ 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;
+}
+
+/* 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 (!VAR_P (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\"");
+
+ set_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
+ DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1;
+
+ return NULL_TREE;
+}
+
+/* Handle a "no_profile_instrument_function" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_no_profile_instrument_function_attribute (tree *node, tree name, tree,
+ int, 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 "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 (position && TREE_CODE (position) != IDENTIFIER_NODE
+ && TREE_CODE (position) != FUNCTION_DECL)
+ position = default_conversion (position);
+
+ if (!tree_fits_uhwi_p (position)
+ || !arg_count
+ || !IN_RANGE (tree_to_uhwi (position), 1, arg_count))
+ {
+ warning (OPT_Wattributes,
+ "alloc_size parameter outside range");
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+ }
+ return NULL_TREE;
+}
+
+/* Handle a "alloc_align" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_alloc_align_attribute (tree *node, tree, tree args, int,
+ bool *no_add_attrs)
+{
+ unsigned arg_count = type_num_arguments (*node);
+ tree position = TREE_VALUE (args);
+ if (position && TREE_CODE (position) != IDENTIFIER_NODE
+ && TREE_CODE (position) != FUNCTION_DECL)
+ position = default_conversion (position);
+
+ if (!tree_fits_uhwi_p (position)
+ || !arg_count
+ || !IN_RANGE (tree_to_uhwi (position), 1, arg_count))
+ {
+ warning (OPT_Wattributes,
+ "alloc_align parameter outside range");
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+ return NULL_TREE;
+}
+
+/* Handle a "assume_aligned" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_assume_aligned_attribute (tree *, tree, tree args, int,
+ bool *no_add_attrs)
+{
+ for (; args; args = TREE_CHAIN (args))
+ {
+ tree position = TREE_VALUE (args);
+ if (position && TREE_CODE (position) != IDENTIFIER_NODE
+ && TREE_CODE (position) != FUNCTION_DECL)
+ position = default_conversion (position);
+
+ if (TREE_CODE (position) != INTEGER_CST)
+ {
+ warning (OPT_Wattributes,
+ "assume_aligned parameter not integer constant");
+ *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 "bnd_variable_size" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_bnd_variable_size_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) != FIELD_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "bnd_legacy" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_bnd_legacy (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 "bnd_instrument" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_bnd_instrument (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 "warn_unused" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_warn_unused_attribute (tree *node, tree name,
+ tree args ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+{
+ if (TYPE_P (*node))
+ /* Do nothing else, just set the attribute. We'll get at
+ it later with lookup_attribute. */
+ ;
+ else
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle an "omp declare simd" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_omp_declare_simd_attribute (tree *, tree, tree, int, bool *)
+{
+ return NULL_TREE;
+}
+
+/* Handle a "simd" attribute. */
+
+static tree
+handle_simd_attribute (tree *node, tree name, tree args, int, bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) == FUNCTION_DECL)
+ {
+ if (lookup_attribute ("cilk simd function",
+ DECL_ATTRIBUTES (*node)) != NULL)
+ {
+ error_at (DECL_SOURCE_LOCATION (*node),
+ "%<__simd__%> attribute cannot be used in the same "
+ "function marked as a Cilk Plus SIMD-enabled function");
+ *no_add_attrs = true;
+ }
+ else
+ {
+ tree t = get_identifier ("omp declare simd");
+ tree attr = NULL_TREE;
+ if (args)
+ {
+ tree 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;
+ }
+
+ if (strcmp (TREE_STRING_POINTER (id), "notinbranch") == 0)
+ attr = build_omp_clause (DECL_SOURCE_LOCATION (*node),
+ OMP_CLAUSE_NOTINBRANCH);
+ else
+ if (strcmp (TREE_STRING_POINTER (id), "inbranch") == 0)
+ attr = build_omp_clause (DECL_SOURCE_LOCATION (*node),
+ OMP_CLAUSE_INBRANCH);
+ else
+ {
+ error ("only %<inbranch%> and %<notinbranch%> flags are "
+ "allowed for %<__simd__%> attribute");
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+ }
+
+ DECL_ATTRIBUTES (*node) = tree_cons (t,
+ build_tree_list (NULL_TREE,
+ attr),
+ DECL_ATTRIBUTES (*node));
+ }
+ }
+ else
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle an "omp declare target" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_omp_declare_target_attribute (tree *, tree, tree, int, bool *)
+{
+ 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;
+}
+
+/* Digest an attribute list destined for a transactional memory statement.
+ ALLOWED is the set of attributes that are allowed for this statement;
+ return the attribute we parsed. Multiple attributes are never allowed. */
+
+int
+parse_tm_stmt_attr (tree attrs, int allowed)
+{
+ tree a_seen = NULL;
+ int m_seen = 0;
+
+ for ( ; attrs ; attrs = TREE_CHAIN (attrs))
+ {
+ tree a = TREE_PURPOSE (attrs);
+ int m = 0;
+
+ if (is_attribute_p ("outer", a))
+ m = TM_STMT_ATTR_OUTER;
+
+ if ((m & allowed) == 0)
+ {
+ warning (OPT_Wattributes, "%qE attribute directive ignored", a);
+ continue;
+ }
+
+ if (m_seen == 0)
+ {
+ a_seen = a;
+ m_seen = m;
+ }
+ else if (m_seen == m)
+ warning (OPT_Wattributes, "%qE attribute duplicated", a);
+ else
+ warning (OPT_Wattributes, "%qE attribute follows %qE", a, a_seen);
+ }
+
+ return m_seen;
+}
+
+/* Transform a TM attribute name into a maskable integer and back.
+ Note that NULL (i.e. no attribute) is mapped to UNKNOWN, corresponding
+ to how the lack of an attribute is treated. */
+
+int
+tm_attr_to_mask (tree attr)
+{
+ if (attr == NULL)
+ return 0;
+ if (is_attribute_p ("transaction_safe", attr))
+ return TM_ATTR_SAFE;
+ if (is_attribute_p ("transaction_callable", attr))
+ return TM_ATTR_CALLABLE;
+ if (is_attribute_p ("transaction_pure", attr))
+ return TM_ATTR_PURE;
+ if (is_attribute_p ("transaction_unsafe", attr))
+ return TM_ATTR_IRREVOCABLE;
+ if (is_attribute_p ("transaction_may_cancel_outer", attr))
+ return TM_ATTR_MAY_CANCEL_OUTER;
+ return 0;
+}
+
+tree
+tm_mask_to_attr (int mask)
+{
+ const char *str;
+ switch (mask)
+ {
+ case TM_ATTR_SAFE:
+ str = "transaction_safe";
+ break;
+ case TM_ATTR_CALLABLE:
+ str = "transaction_callable";
+ break;
+ case TM_ATTR_PURE:
+ str = "transaction_pure";
+ break;
+ case TM_ATTR_IRREVOCABLE:
+ str = "transaction_unsafe";
+ break;
+ case TM_ATTR_MAY_CANCEL_OUTER:
+ str = "transaction_may_cancel_outer";
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ return get_identifier (str);
+}
+
+/* Return the first TM attribute seen in LIST. */
+
+tree
+find_tm_attribute (tree list)
+{
+ for (; list ; list = TREE_CHAIN (list))
+ {
+ tree name = TREE_PURPOSE (list);
+ if (tm_attr_to_mask (name) != 0)
+ return name;
+ }
+ return NULL_TREE;
+}
+
+/* Handle the TM attributes; arguments as in struct attribute_spec.handler.
+ Here we accept only function types, and verify that none of the other
+ function TM attributes are also applied. */
+/* ??? We need to accept class types for C++, but not C. This greatly
+ complicates this function, since we can no longer rely on the extra
+ processing given by function_type_required. */
+
+static tree
+handle_tm_attribute (tree *node, tree name, tree args,
+ int flags, bool *no_add_attrs)
+{
+ /* Only one path adds the attribute; others don't. */
+ *no_add_attrs = true;
+
+ switch (TREE_CODE (*node))
+ {
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ /* Only tm_callable and tm_safe apply to classes. */
+ if (tm_attr_to_mask (name) & ~(TM_ATTR_SAFE | TM_ATTR_CALLABLE))
+ goto ignored;
+ /* FALLTHRU */
+
+ case FUNCTION_TYPE:
+ case METHOD_TYPE:
+ {
+ tree old_name = find_tm_attribute (TYPE_ATTRIBUTES (*node));
+ if (old_name == name)
+ ;
+ else if (old_name != NULL_TREE)
+ error ("type was previously declared %qE", old_name);
+ else
+ *no_add_attrs = false;
+ }
+ break;
+
+ case FUNCTION_DECL:
+ {
+ /* transaction_safe_dynamic goes on the FUNCTION_DECL, but we also
+ want to set transaction_safe on the type. */
+ gcc_assert (is_attribute_p ("transaction_safe_dynamic", name));
+ if (!TYPE_P (DECL_CONTEXT (*node)))
+ error_at (DECL_SOURCE_LOCATION (*node),
+ "%<transaction_safe_dynamic%> may only be specified for "
+ "a virtual function");
+ *no_add_attrs = false;
+ decl_attributes (&TREE_TYPE (*node),
+ build_tree_list (get_identifier ("transaction_safe"),
+ NULL_TREE),
+ 0);
+ break;
+ }
+
+ case POINTER_TYPE:
+ {
+ enum tree_code subcode = TREE_CODE (TREE_TYPE (*node));
+ if (subcode == FUNCTION_TYPE || subcode == METHOD_TYPE)
+ {
+ tree fn_tmp = TREE_TYPE (*node);
+ decl_attributes (&fn_tmp, tree_cons (name, args, NULL), 0);
+ *node = build_pointer_type (fn_tmp);
+ break;
+ }
+ }
+ /* FALLTHRU */
+
+ default:
+ /* If a function is next, pass it on to be tried next. */
+ if (flags & (int) ATTR_FLAG_FUNCTION_NEXT)
+ return tree_cons (name, args, NULL);
+
+ ignored:
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ break;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle the TM_WRAP attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_tm_wrap_attribute (tree *node, tree name, tree args,
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ tree decl = *node;
+
+ /* We don't need the attribute even on success, since we
+ record the entry in an external table. */
+ *no_add_attrs = true;
+
+ if (TREE_CODE (decl) != FUNCTION_DECL)
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ else
+ {
+ tree wrap_decl = TREE_VALUE (args);
+ if (error_operand_p (wrap_decl))
+ ;
+ else if (TREE_CODE (wrap_decl) != IDENTIFIER_NODE
+ && !VAR_OR_FUNCTION_DECL_P (wrap_decl))
+ error ("%qE argument not an identifier", name);
+ else
+ {
+ if (TREE_CODE (wrap_decl) == IDENTIFIER_NODE)
+ wrap_decl = lookup_name (wrap_decl);
+ if (wrap_decl && TREE_CODE (wrap_decl) == FUNCTION_DECL)
+ {
+ if (lang_hooks.types_compatible_p (TREE_TYPE (decl),
+ TREE_TYPE (wrap_decl)))
+ record_tm_replacement (wrap_decl, decl);
+ else
+ error ("%qD is not compatible with %qD", wrap_decl, decl);
+ }
+ else
+ error ("%qE argument is not a function", name);
+ }
+ }
+
+ return NULL_TREE;
+}
+
+/* Ignore the given attribute. Used when this attribute may be usefully
+ overridden by the target, but is not used generically. */
+
+static tree
+ignore_attribute (tree * ARG_UNUSED (node), tree ARG_UNUSED (name),
+ tree ARG_UNUSED (args), int ARG_UNUSED (flags),
+ bool *no_add_attrs)
+{
+ *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
+ || VAR_OR_FUNCTION_DECL_P (decl)
+ || TREE_CODE (decl) == FIELD_DECL
+ || TREE_CODE (decl) == CONST_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;
+ machine_mode orig_mode;
+ tree type = *node, new_type, size;
+
+ *no_add_attrs = true;
+
+ size = TREE_VALUE (args);
+ if (size && TREE_CODE (size) != IDENTIFIER_NODE
+ && TREE_CODE (size) != FUNCTION_DECL)
+ size = default_conversion (size);
+
+ if (!tree_fits_uhwi_p (size))
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ return NULL_TREE;
+ }
+
+ /* Get the vector size (in bytes). */
+ vecsize = tree_to_uhwi (size);
+
+ /* 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))
+ || !tree_fits_uhwi_p (TYPE_SIZE_UNIT (type))
+ || TREE_CODE (type) == BOOLEAN_TYPE)
+ {
+ error ("invalid vector type for attribute %qE", name);
+ return NULL_TREE;
+ }
+
+ if (vecsize % tree_to_uhwi (TYPE_SIZE_UNIT (type)))
+ {
+ 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_to_uhwi (TYPE_SIZE_UNIT (type));
+ 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.
+ Avoid diagnosing type-generic built-ins since those have no
+ prototype. */
+ if (!args)
+ {
+ if (!prototype_p (type)
+ && (!TYPE_ATTRIBUTES (type)
+ || !lookup_attribute ("type generic", TYPE_ATTRIBUTES (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; attr_arg_num++, args = TREE_CHAIN (args))
+ {
+ unsigned HOST_WIDE_INT arg_num = 0, ck_num;
+
+ tree arg = TREE_VALUE (args);
+ if (arg && TREE_CODE (arg) != IDENTIFIER_NODE
+ && TREE_CODE (arg) != FUNCTION_DECL)
+ TREE_VALUE (args) = arg = default_conversion (arg);
+
+ if (!get_nonnull_operand (arg, &arg_num))
+ {
+ error ("nonnull argument has invalid operand number (argument %lu)",
+ (unsigned long) attr_arg_num);
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+
+ if (prototype_p (type))
+ {
+ function_args_iterator iter;
+ tree argument;
+
+ function_args_iter_init (&iter, type);
+ for (ck_num = 1; ; ck_num++, function_args_iter_next (&iter))
+ {
+ argument = function_args_iter_cond (&iter);
+ if (argument == NULL_TREE || ck_num == arg_num)
+ break;
+ }
+
+ if (!argument
+ || TREE_CODE (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 (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;
+}
+
+/* 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 (!VAR_P (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)
+{
+ if (!prototype_p (*node))
+ {
+ warning (OPT_Wattributes,
+ "%qE attribute requires prototypes with named arguments", name);
+ *no_add_attrs = true;
+ }
+ else
+ {
+ if (!stdarg_p (*node))
+ {
+ warning (OPT_Wattributes,
+ "%qE attribute only applies to variadic functions", name);
+ *no_add_attrs = true;
+ }
+ }
+
+ if (args)
+ {
+ tree position = TREE_VALUE (args);
+ if (position && TREE_CODE (position) != IDENTIFIER_NODE
+ && TREE_CODE (position) != FUNCTION_DECL)
+ position = default_conversion (position);
+
+ if (TREE_CODE (position) != INTEGER_CST
+ || !INTEGRAL_TYPE_P (TREE_TYPE (position)))
+ {
+ 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))
+{
+ /* Ensure we have a function type. */
+ gcc_assert (TREE_CODE (*node) == FUNCTION_TYPE);
+
+ /* Ensure we have a variadic function. */
+ gcc_assert (!prototype_p (*node) || stdarg_p (*node));
+
+ 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 (lookup_attribute ("target_clones", DECL_ATTRIBUTES (*node)))
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
+ "with %qs attribute", name, "target_clones");
+ *no_add_attrs = true;
+ }
+ else if (! targetm.target_option.valid_attribute_p (*node, name, args,
+ flags))
+ *no_add_attrs = true;
+
+ return NULL_TREE;
+}
+
+/* Handle a "target_clones" attribute. */
+
+static tree
+handle_target_clones_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ /* Ensure we have a function type. */
+ if (TREE_CODE (*node) == FUNCTION_DECL)
+ {
+ if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (*node)))
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
+ "with %qs attribute", name, "always_inline");
+ *no_add_attrs = true;
+ }
+ else if (lookup_attribute ("target", DECL_ATTRIBUTES (*node)))
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
+ "with %qs attribute", name, "target");
+ *no_add_attrs = true;
+ }
+ else
+ /* Do not inline functions with multiple clone targets. */
+ DECL_UNINLINABLE (*node) = 1;
+ }
+ else
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+ return NULL_TREE;
+}
+
+/* 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 (&global_options);
+
+ /* 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;
+}
+
+/* Handle a "returns_nonnull" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_returns_nonnull_attribute (tree *node, tree, tree, int,
+ bool *no_add_attrs)
+{
+ // Even without a prototype we still have a return type we can check.
+ if (TREE_CODE (TREE_TYPE (*node)) != POINTER_TYPE)
+ {
+ error ("returns_nonnull attribute on a function not returning a pointer");
+ *no_add_attrs = true;
+ }
+ return NULL_TREE;
+}
+
+/* Handle a "designated_init" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_designated_init_attribute (tree *node, tree name, tree, int,
+ bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) != RECORD_TYPE)
+ {
+ error ("%qE attribute is only valid on %<struct%> type", name);
+ *no_add_attrs = true;
+ }
+ return NULL_TREE;
+}
+
+
+/* Handle a "fallthrough" attribute; arguments as in struct
+ attribute_spec.handler. */
+
+static tree
+handle_fallthrough_attribute (tree *, tree name, tree, int,
+ bool *no_add_attrs)
+{
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ return NULL_TREE;
+}
diff --git a/gcc/c-family/c-cilkplus.c b/gcc/c-family/c-cilkplus.c
index 3e7902fd11..a537193798 100644
--- a/gcc/c-family/c-cilkplus.c
+++ b/gcc/c-family/c-cilkplus.c
@@ -1,7 +1,7 @@
/* This file contains routines to construct and validate Cilk Plus
constructs within the C and C++ front ends.
- Copyright (C) 2013-2016 Free Software Foundation, Inc.
+ Copyright (C) 2013-2017 Free Software Foundation, Inc.
Contributed by Aldy Hernandez <aldyh@redhat.com>.
This file is part of GCC.
@@ -41,56 +41,6 @@ c_check_cilk_loop (location_t loc, tree decl)
return true;
}
-/* Validate and emit code for <#pragma simd> clauses. */
-
-tree
-c_finish_cilk_clauses (tree clauses)
-{
- for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
- {
- tree prev = clauses;
-
- /* If a variable appears in a linear clause it cannot appear in
- any other OMP clause. */
- if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR)
- for (tree c2 = clauses; c2; c2 = OMP_CLAUSE_CHAIN (c2))
- {
- if (c == c2)
- continue;
- enum omp_clause_code code = OMP_CLAUSE_CODE (c2);
-
- switch (code)
- {
- case OMP_CLAUSE_LINEAR:
- case OMP_CLAUSE_PRIVATE:
- case OMP_CLAUSE_FIRSTPRIVATE:
- case OMP_CLAUSE_LASTPRIVATE:
- case OMP_CLAUSE_REDUCTION:
- break;
-
- case OMP_CLAUSE_SAFELEN:
- goto next;
-
- default:
- gcc_unreachable ();
- }
-
- if (OMP_CLAUSE_DECL (c) == OMP_CLAUSE_DECL (c2))
- {
- error_at (OMP_CLAUSE_LOCATION (c2),
- "variable appears in more than one clause");
- inform (OMP_CLAUSE_LOCATION (c),
- "other clause defined here");
- // Remove problematic clauses.
- OMP_CLAUSE_CHAIN (prev) = OMP_CLAUSE_CHAIN (c2);
- }
- next:
- prev = c2;
- }
- }
- return clauses;
-}
-
/* Calculate number of iterations of CILK_FOR. */
tree
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index f2846bb26e..0a7f673cbb 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -1,5 +1,5 @@
/* Subroutines shared by all languages that are variants of C.
- Copyright (C) 1992-2016 Free Software Foundation, Inc.
+ Copyright (C) 1992-2017 Free Software Foundation, Inc.
This file is part of GCC.
@@ -25,6 +25,7 @@ along with GCC; see the file COPYING3. If not see
#include "target.h"
#include "function.h"
#include "tree.h"
+#include "memmodel.h"
#include "c-common.h"
#include "gimple-expr.h"
#include "tm_p.h"
@@ -45,6 +46,8 @@ along with GCC; see the file COPYING3. If not see
#include "tree-iterator.h"
#include "opts.h"
#include "gimplify.h"
+#include "substring-locations.h"
+#include "spellcheck.h"
cpp_reader *parse_in; /* Declared in c-pragma.h. */
@@ -303,100 +306,9 @@ static tree check_case_value (location_t, tree);
static bool check_case_bounds (location_t, tree, tree, tree *, tree *,
bool *);
-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_no_sanitize_address_attribute (tree *, tree, tree,
- int, bool *);
-static tree handle_no_address_safety_analysis_attribute (tree *, tree, tree,
- int, bool *);
-static tree handle_no_sanitize_undefined_attribute (tree *, tree, tree, int,
- bool *);
-static tree handle_stack_protect_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_noicf_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_no_reorder_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_scalar_storage_order_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_noplt_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_tm_attribute (tree *, tree, tree, int, bool *);
-static tree handle_tm_wrap_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_alloc_align_attribute (tree *, tree, tree, int, bool *);
-static tree handle_assume_aligned_attribute (tree *, tree, tree, int, bool *);
-static tree handle_target_attribute (tree *, tree, tree, int, bool *);
-static tree handle_target_clones_attribute (tree *, tree, tree, int, bool *);
-static tree handle_optimize_attribute (tree *, tree, tree, int, bool *);
-static tree ignore_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 tree handle_warn_unused_attribute (tree *, tree, tree, int, bool *);
-static tree handle_returns_nonnull_attribute (tree *, tree, tree, int, bool *);
-static tree handle_omp_declare_simd_attribute (tree *, tree, tree, int,
- bool *);
-static tree handle_simd_attribute (tree *, tree, tree, int, bool *);
-static tree handle_omp_declare_target_attribute (tree *, tree, tree, int,
- bool *);
-static tree handle_designated_init_attribute (tree *, tree, tree, int, bool *);
-static tree handle_bnd_variable_size_attribute (tree *, tree, tree, int, bool *);
-static tree handle_bnd_legacy (tree *, tree, tree, int, bool *);
-static tree handle_bnd_instrument (tree *, tree, tree, int, bool *);
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
@@ -406,8 +318,8 @@ static int resort_field_decl_cmp (const void *, const void *);
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
+ C++ --std=c++98: D_CONLY | D_CXX11 | D_OBJC
+ C++ --std=c++11: 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
@@ -431,6 +343,13 @@ const struct c_common_resword c_common_reswords[] =
{ "_Cilk_sync", RID_CILK_SYNC, 0 },
{ "_Cilk_for", RID_CILK_FOR, 0 },
{ "_Imaginary", RID_IMAGINARY, D_CONLY },
+ { "_Float16", RID_FLOAT16, D_CONLY },
+ { "_Float32", RID_FLOAT32, D_CONLY },
+ { "_Float64", RID_FLOAT64, D_CONLY },
+ { "_Float128", RID_FLOAT128, D_CONLY },
+ { "_Float32x", RID_FLOAT32X, D_CONLY },
+ { "_Float64x", RID_FLOAT64X, D_CONLY },
+ { "_Float128x", RID_FLOAT128X, D_CONLY },
{ "_Decimal32", RID_DFLOAT32, D_CONLY | D_EXT },
{ "_Decimal64", RID_DFLOAT64, D_CONLY | D_EXT },
{ "_Decimal128", RID_DFLOAT128, D_CONLY | D_EXT },
@@ -451,10 +370,12 @@ const struct c_common_resword c_common_reswords[] =
{ "__attribute__", RID_ATTRIBUTE, 0 },
{ "__auto_type", RID_AUTO_TYPE, D_CONLY },
{ "__bases", RID_BASES, D_CXXONLY },
+ { "__builtin_addressof", RID_ADDRESSOF, D_CXXONLY },
{ "__builtin_call_with_static_chain",
RID_BUILTIN_CALL_WITH_STATIC_CHAIN, D_CONLY },
{ "__builtin_choose_expr", RID_CHOOSE_EXPR, D_CONLY },
{ "__builtin_complex", RID_BUILTIN_COMPLEX, D_CONLY },
+ { "__builtin_launder", RID_BUILTIN_LAUNDER, D_CXXONLY },
{ "__builtin_shuffle", RID_BUILTIN_SHUFFLE, 0 },
{ "__builtin_offsetof", RID_OFFSETOF, 0 },
{ "__builtin_types_compatible_p", RID_TYPES_COMPATIBLE_P, D_CONLY },
@@ -474,12 +395,15 @@ const struct c_common_resword c_common_reswords[] =
{ "__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_unique_object_representations", RID_HAS_UNIQUE_OBJ_REPRESENTATIONS,
+ D_CXXONLY },
{ "__has_virtual_destructor", RID_HAS_VIRTUAL_DESTRUCTOR, D_CXXONLY },
{ "__imag", RID_IMAGPART, 0 },
{ "__imag__", RID_IMAGPART, 0 },
{ "__inline", RID_INLINE, 0 },
{ "__inline__", RID_INLINE, 0 },
{ "__is_abstract", RID_IS_ABSTRACT, D_CXXONLY },
+ { "__is_aggregate", RID_IS_AGGREGATE, D_CXXONLY },
{ "__is_base_of", RID_IS_BASE_OF, D_CXXONLY },
{ "__is_class", RID_IS_CLASS, D_CXXONLY },
{ "__is_empty", RID_IS_EMPTY, D_CXXONLY },
@@ -512,6 +436,9 @@ const struct c_common_resword c_common_reswords[] =
{ "__underlying_type", RID_UNDERLYING_TYPE, D_CXXONLY },
{ "__volatile", RID_VOLATILE, 0 },
{ "__volatile__", RID_VOLATILE, 0 },
+ { "__GIMPLE", RID_GIMPLE, D_CONLY },
+ { "__PHI", RID_PHI, D_CONLY },
+ { "__RTL", RID_RTL, D_CONLY },
{ "alignas", RID_ALIGNAS, D_CXXONLY | D_CXX11 | D_CXXWARN },
{ "alignof", RID_ALIGNOF, D_CXXONLY | D_CXX11 | D_CXXWARN },
{ "asm", RID_ASM, D_ASM },
@@ -637,224 +564,6 @@ const struct c_common_resword c_common_reswords[] =
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.
-
- All attributes referencing arguments should be additionally processed
- in chkp_copy_function_type_adding_bounds for correct instrumentation
- by Pointer Bounds Checker.
- Current list of processed common attributes: nonnull. */
-const struct attribute_spec c_common_attribute_table[] =
-{
- /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
- affects_type_identity } */
- { "packed", 0, 0, false, false, false,
- handle_packed_attribute , false},
- { "nocommon", 0, 0, true, false, false,
- handle_nocommon_attribute, false},
- { "common", 0, 0, true, false, false,
- handle_common_attribute, false },
- /* 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, false },
- { "volatile", 0, 0, true, false, false,
- handle_noreturn_attribute, false },
- { "stack_protect", 0, 0, true, false, false,
- handle_stack_protect_attribute, false },
- { "noinline", 0, 0, true, false, false,
- handle_noinline_attribute, false },
- { "noclone", 0, 0, true, false, false,
- handle_noclone_attribute, false },
- { "no_icf", 0, 0, true, false, false,
- handle_noicf_attribute, false },
- { "leaf", 0, 0, true, false, false,
- handle_leaf_attribute, false },
- { "always_inline", 0, 0, true, false, false,
- handle_always_inline_attribute, false },
- { "gnu_inline", 0, 0, true, false, false,
- handle_gnu_inline_attribute, false },
- { "artificial", 0, 0, true, false, false,
- handle_artificial_attribute, false },
- { "flatten", 0, 0, true, false, false,
- handle_flatten_attribute, false },
- { "used", 0, 0, true, false, false,
- handle_used_attribute, false },
- { "unused", 0, 0, false, false, false,
- handle_unused_attribute, false },
- { "externally_visible", 0, 0, true, false, false,
- handle_externally_visible_attribute, false },
- { "no_reorder", 0, 0, true, false, false,
- handle_no_reorder_attribute, false },
- /* The same comments as for noreturn attributes apply to const ones. */
- { "const", 0, 0, true, false, false,
- handle_const_attribute, false },
- { "scalar_storage_order", 1, 1, false, false, false,
- handle_scalar_storage_order_attribute, false },
- { "transparent_union", 0, 0, false, false, false,
- handle_transparent_union_attribute, false },
- { "constructor", 0, 1, true, false, false,
- handle_constructor_attribute, false },
- { "destructor", 0, 1, true, false, false,
- handle_destructor_attribute, false },
- { "mode", 1, 1, false, true, false,
- handle_mode_attribute, false },
- { "section", 1, 1, true, false, false,
- handle_section_attribute, false },
- { "aligned", 0, 1, false, false, false,
- handle_aligned_attribute, false },
- { "weak", 0, 0, true, false, false,
- handle_weak_attribute, false },
- { "noplt", 0, 0, true, false, false,
- handle_noplt_attribute, false },
- { "ifunc", 1, 1, true, false, false,
- handle_ifunc_attribute, false },
- { "alias", 1, 1, true, false, false,
- handle_alias_attribute, false },
- { "weakref", 0, 1, true, false, false,
- handle_weakref_attribute, false },
- { "no_instrument_function", 0, 0, true, false, false,
- handle_no_instrument_function_attribute,
- false },
- { "malloc", 0, 0, true, false, false,
- handle_malloc_attribute, false },
- { "returns_twice", 0, 0, true, false, false,
- handle_returns_twice_attribute, false },
- { "no_stack_limit", 0, 0, true, false, false,
- handle_no_limit_stack_attribute, false },
- { "pure", 0, 0, true, false, false,
- handle_pure_attribute, false },
- { "transaction_callable", 0, 0, false, true, false,
- handle_tm_attribute, false },
- { "transaction_unsafe", 0, 0, false, true, false,
- handle_tm_attribute, true },
- { "transaction_safe", 0, 0, false, true, false,
- handle_tm_attribute, true },
- { "transaction_safe_dynamic", 0, 0, true, false, false,
- handle_tm_attribute, false },
- { "transaction_may_cancel_outer", 0, 0, false, true, false,
- handle_tm_attribute, false },
- /* ??? These two attributes didn't make the transition from the
- Intel language document to the multi-vendor language document. */
- { "transaction_pure", 0, 0, false, true, false,
- handle_tm_attribute, false },
- { "transaction_wrap", 1, 1, true, false, false,
- handle_tm_wrap_attribute, false },
- /* 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, false },
- { "deprecated", 0, 1, false, false, false,
- handle_deprecated_attribute, false },
- { "vector_size", 1, 1, false, true, false,
- handle_vector_size_attribute, false },
- { "visibility", 1, 1, false, false, false,
- handle_visibility_attribute, false },
- { "tls_model", 1, 1, true, false, false,
- handle_tls_model_attribute, false },
- { "nonnull", 0, -1, false, true, true,
- handle_nonnull_attribute, false },
- { "nothrow", 0, 0, true, false, false,
- handle_nothrow_attribute, false },
- { "may_alias", 0, 0, false, true, false, NULL, false },
- { "cleanup", 1, 1, true, false, false,
- handle_cleanup_attribute, false },
- { "warn_unused_result", 0, 0, false, true, true,
- handle_warn_unused_result_attribute, false },
- { "sentinel", 0, 1, false, true, true,
- handle_sentinel_attribute, false },
- /* 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, false },
- { "alloc_size", 1, 2, false, true, true,
- handle_alloc_size_attribute, false },
- { "cold", 0, 0, true, false, false,
- handle_cold_attribute, false },
- { "hot", 0, 0, true, false, false,
- handle_hot_attribute, false },
- { "no_address_safety_analysis",
- 0, 0, true, false, false,
- handle_no_address_safety_analysis_attribute,
- false },
- { "no_sanitize_address", 0, 0, true, false, false,
- handle_no_sanitize_address_attribute,
- false },
- { "no_sanitize_thread", 0, 0, true, false, false,
- handle_no_sanitize_address_attribute,
- false },
- { "no_sanitize_undefined", 0, 0, true, false, false,
- handle_no_sanitize_undefined_attribute,
- false },
- { "warning", 1, 1, true, false, false,
- handle_error_attribute, false },
- { "error", 1, 1, true, false, false,
- handle_error_attribute, false },
- { "target", 1, -1, true, false, false,
- handle_target_attribute, false },
- { "target_clones", 1, -1, true, false, false,
- handle_target_clones_attribute, false },
- { "optimize", 1, -1, true, false, false,
- handle_optimize_attribute, false },
- /* For internal use only. The leading '*' both prevents its usage in
- source code and signals that it may be overridden by machine tables. */
- { "*tm regparm", 0, 0, false, true, true,
- ignore_attribute, false },
- { "no_split_stack", 0, 0, true, false, false,
- handle_no_split_stack_attribute, false },
- /* 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, false },
- { "warn_unused", 0, 0, false, false, false,
- handle_warn_unused_attribute, false },
- { "returns_nonnull", 0, 0, false, true, true,
- handle_returns_nonnull_attribute, false },
- { "omp declare simd", 0, -1, true, false, false,
- handle_omp_declare_simd_attribute, false },
- { "cilk simd function", 0, -1, true, false, false,
- handle_omp_declare_simd_attribute, false },
- { "simd", 0, 1, true, false, false,
- handle_simd_attribute, false },
- { "omp declare target", 0, 0, true, false, false,
- handle_omp_declare_target_attribute, false },
- { "omp declare target link", 0, 0, true, false, false,
- handle_omp_declare_target_attribute, false },
- { "alloc_align", 1, 1, false, true, true,
- handle_alloc_align_attribute, false },
- { "assume_aligned", 1, 2, false, true, true,
- handle_assume_aligned_attribute, false },
- { "designated_init", 0, 0, false, true, false,
- handle_designated_init_attribute, false },
- { "bnd_variable_size", 0, 0, true, false, false,
- handle_bnd_variable_size_attribute, false },
- { "bnd_legacy", 0, 0, true, false, false,
- handle_bnd_legacy, false },
- { "bnd_instrument", 0, 0, true, false, false,
- handle_bnd_instrument, false },
- { NULL, 0, 0, false, false, false, NULL, false }
-};
-
-/* Give the specifications for the format attributes, used by C and all
- descendants.
-
- All attributes referencing arguments should be additionally processed
- in chkp_copy_function_type_adding_bounds for correct instrumentation
- by Pointer Bounds Checker.
- Current list of processed format attributes: format, format_arg. */
-const struct attribute_spec c_common_format_attribute_table[] =
-{
- /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
- affects_type_identity } */
- { "format", 3, 3, false, true, true,
- handle_format_attribute, false },
- { "format_arg", 1, 1, false, true, true,
- handle_format_arg_attribute, false },
- { NULL, 0, 0, false, false, false, NULL, false }
-};
-
/* Return identifier for address space AS. */
const char *
@@ -1094,867 +803,92 @@ fix_string_type (tree value)
TREE_STATIC (value) = 1;
return value;
}
-
-/* Fold X for consideration by one of the warning functions when checking
- whether an expression has a constant value. */
-
-static tree
-fold_for_warn (tree x)
-{
- if (c_dialect_cxx ())
- return c_fully_fold (x, /*for_init*/false, /*maybe_constp*/NULL);
- else
- /* The C front-end has already folded X appropriately. */
- return x;
-}
-/* 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. */
+/* Given a string of type STRING_TYPE, determine what kind of string
+ token would give an equivalent execution encoding: CPP_STRING,
+ CPP_STRING16, or CPP_STRING32. Return CPP_OTHER in case of error.
+ This may not be exactly the string token type that initially created
+ the string, since CPP_WSTRING is indistinguishable from the 16/32 bit
+ string type at this point.
-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");
-}
+ This effectively reverses part of the logic in lex_string and
+ fix_string_type. */
-/* The same as above but print an unconditional error. */
-void
-constant_expression_error (tree value)
+static enum cpp_ttype
+get_cpp_ttype_from_string_type (tree string_type)
{
- 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");
-}
+ gcc_assert (string_type);
+ if (TREE_CODE (string_type) == POINTER_TYPE)
+ string_type = TREE_TYPE (string_type);
-/* Print a warning if an expression had overflow in folding and its
- operands hadn't.
+ if (TREE_CODE (string_type) != ARRAY_TYPE)
+ return CPP_OTHER;
- 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;
+ tree element_type = TREE_TYPE (string_type);
+ if (TREE_CODE (element_type) != INTEGER_TYPE)
+ return CPP_OTHER;
- switch (TREE_CODE (value))
+ int bits_per_character = TYPE_PRECISION (element_type);
+ switch (bits_per_character)
{
- 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;
-
- /* We don't want to warn if either operand comes from a macro
- expansion. ??? This doesn't work with e.g. NEGATE_EXPR yet;
- see PR61534. */
- if (from_macro_expansion_at (EXPR_LOCATION (op_left))
- || from_macro_expansion_at (EXPR_LOCATION (op_right)))
- 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 (TREE_CODE (op_right) == CONST_DECL)
- /* An enumerator counts as a constant. */
- op_right = DECL_INITIAL (op_right);
- 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 (fold_for_warn (op_left))
- || CONSTANT_CLASS_P (fold_for_warn (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;
-
- /* The range computations only work with scalars. */
- if (VECTOR_TYPE_P (TREE_TYPE (op_left))
- || VECTOR_TYPE_P (TREE_TYPE (op_right)))
- return;
-
- /* We first test whether either side separately is trivially true
- (with OR) or trivially false (with AND). If so, do not warn.
- This is a common idiom for testing ranges of data types in
- portable code. */
- lhs = make_range (op_left, &in0_p, &low0, &high0, &strict_overflow_p);
- if (!lhs)
- return;
- if (TREE_CODE (lhs) == C_MAYBE_CONST_EXPR)
- lhs = C_MAYBE_CONST_EXPR_EXPR (lhs);
-
- /* If this is an OR operation, invert both sides; now, the result
- should be always false to get a warning. */
- if (or_op)
- in0_p = !in0_p;
-
- tem = build_range_check (UNKNOWN_LOCATION, type, lhs, in0_p, low0, high0);
- if (tem && integer_zerop (tem))
- return;
-
- rhs = make_range (op_right, &in1_p, &low1, &high1, &strict_overflow_p);
- if (!rhs)
- return;
- if (TREE_CODE (rhs) == C_MAYBE_CONST_EXPR)
- rhs = C_MAYBE_CONST_EXPR_EXPR (rhs);
-
- /* If this is an OR operation, invert both sides; now, the result
- should be always false to get a warning. */
- if (or_op)
- in1_p = !in1_p;
-
- tem = build_range_check (UNKNOWN_LOCATION, type, rhs, in1_p, low1, high1);
- if (tem && integer_zerop (tem))
- return;
-
- /* If both expressions have the same operand, if we can merge the
- ranges, ... */
- if (operand_equal_p (lhs, rhs, 0)
- && merge_ranges (&in_p, &low, &high, in0_p, low0, high0,
- in1_p, low1, high1))
- {
- tem = build_range_check (UNKNOWN_LOCATION, type, lhs, in_p, low, high);
- /* ... and if the range test is always false, then warn. */
- if (tem && integer_zerop (tem))
- {
- 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");
- }
- /* Or warn if the operands have exactly the same range, e.g.
- A > 0 && A > 0. */
- else if (tree_int_cst_equal (low0, low1)
- && tree_int_cst_equal (high0, high1))
- {
- if (or_op)
- warning_at (location, OPT_Wlogical_op,
- "logical %<or%> of equal expressions");
- else
- warning_at (location, OPT_Wlogical_op,
- "logical %<and%> of equal expressions");
- }
- }
-}
-
-/* Helper function for warn_tautological_cmp. Look for ARRAY_REFs
- with constant indices. */
-
-static tree
-find_array_ref_with_const_idx_r (tree *expr_p, int *walk_subtrees, void *data)
-{
- tree expr = *expr_p;
-
- if ((TREE_CODE (expr) == ARRAY_REF
- || TREE_CODE (expr) == ARRAY_RANGE_REF)
- && TREE_CODE (TREE_OPERAND (expr, 1)) == INTEGER_CST)
- {
- *(bool *) data = true;
- *walk_subtrees = 0;
+ case 8:
+ return CPP_STRING; /* It could have also been CPP_UTF8STRING. */
+ case 16:
+ return CPP_STRING16;
+ case 32:
+ return CPP_STRING32;
}
- return NULL_TREE;
+ return CPP_OTHER;
}
-/* Warn if a self-comparison always evaluates to true or false. LOC
- is the location of the comparison with code CODE, LHS and RHS are
- operands of the comparison. */
-
-void
-warn_tautological_cmp (location_t loc, enum tree_code code, tree lhs, tree rhs)
-{
- if (TREE_CODE_CLASS (code) != tcc_comparison)
- return;
-
- /* Don't warn for various macro expansions. */
- if (from_macro_expansion_at (loc)
- || from_macro_expansion_at (EXPR_LOCATION (lhs))
- || from_macro_expansion_at (EXPR_LOCATION (rhs)))
- return;
+/* The global record of string concatentations, for use in
+ extracting locations within string literals. */
- /* We do not warn for constants because they are typical of macro
- expansions that test for features, sizeof, and similar. */
- if (CONSTANT_CLASS_P (fold_for_warn (lhs))
- || CONSTANT_CLASS_P (fold_for_warn (rhs)))
- return;
+GTY(()) string_concat_db *g_string_concat_db;
- /* Don't warn for e.g.
- HOST_WIDE_INT n;
- ...
- if (n == (long) n) ...
- */
- if ((CONVERT_EXPR_P (lhs) || TREE_CODE (lhs) == NON_LVALUE_EXPR)
- || (CONVERT_EXPR_P (rhs) || TREE_CODE (rhs) == NON_LVALUE_EXPR))
- return;
+/* Implementation of LANG_HOOKS_GET_SUBSTRING_LOCATION. */
- /* Don't warn if either LHS or RHS has an IEEE floating-point type.
- It could be a NaN, and NaN never compares equal to anything, even
- itself. */
- if (FLOAT_TYPE_P (TREE_TYPE (lhs)) || FLOAT_TYPE_P (TREE_TYPE (rhs)))
- return;
-
- if (operand_equal_p (lhs, rhs, 0))
- {
- /* Don't warn about array references with constant indices;
- these are likely to come from a macro. */
- bool found = false;
- walk_tree_without_duplicates (&lhs, find_array_ref_with_const_idx_r,
- &found);
- if (found)
- return;
- const bool always_true = (code == EQ_EXPR || code == LE_EXPR
- || code == GE_EXPR || code == UNLE_EXPR
- || code == UNGE_EXPR || code == UNEQ_EXPR);
- if (always_true)
- warning_at (loc, OPT_Wtautological_compare,
- "self-comparison always evaluates to true");
- else
- warning_at (loc, OPT_Wtautological_compare,
- "self-comparison always evaluates to false");
- }
-}
-
-/* Warn about logical not used on the left hand side operand of a comparison.
- This function assumes that the LHS is inside of TRUTH_NOT_EXPR.
- Do not warn if RHS is of a boolean type. */
-
-void
-warn_logical_not_parentheses (location_t location, enum tree_code code,
- tree rhs)
+const char *
+c_get_substring_location (const substring_loc &substr_loc,
+ location_t *out_loc)
{
- if (TREE_CODE_CLASS (code) != tcc_comparison
- || TREE_TYPE (rhs) == NULL_TREE
- || TREE_CODE (TREE_TYPE (rhs)) == BOOLEAN_TYPE)
- return;
-
- /* Don't warn for !x == 0 or !y != 0, those are equivalent to
- !(x == 0) or !(y != 0). */
- if ((code == EQ_EXPR || code == NE_EXPR)
- && integer_zerop (rhs))
- return;
+ enum cpp_ttype tok_type
+ = get_cpp_ttype_from_string_type (substr_loc.get_string_type ());
+ if (tok_type == CPP_OTHER)
+ return "unrecognized string type";
- warning_at (location, OPT_Wlogical_not_parentheses,
- "logical not is only applied to the left hand side of "
- "comparison");
+ return get_source_location_for_substring (parse_in, g_string_concat_db,
+ substr_loc.get_fmt_string_loc (),
+ tok_type,
+ substr_loc.get_caret_idx (),
+ substr_loc.get_start_idx (),
+ substr_loc.get_end_idx (),
+ out_loc);
}
-/* Warn if EXP contains any computations whose results are not used.
- Return true if a warning is printed; false otherwise. LOCUS is the
- (potential) location of the expression. */
+
+/* Fold X for consideration by one of the warning functions when checking
+ whether an expression has a constant value. */
-bool
-warn_if_unused_value (const_tree exp, location_t locus)
+tree
+fold_for_warn (tree x)
{
- restart:
- if (TREE_USED (exp) || TREE_NO_WARNING (exp))
- return false;
-
- /* Don't warn about void constructs. This includes casting to void,
- void function calls, and statement expressions with a final cast
- to void. */
- if (VOID_TYPE_P (TREE_TYPE (exp)))
- return false;
-
- if (EXPR_HAS_LOCATION (exp))
- locus = EXPR_LOCATION (exp);
-
- switch (TREE_CODE (exp))
- {
- case PREINCREMENT_EXPR:
- case POSTINCREMENT_EXPR:
- case PREDECREMENT_EXPR:
- case POSTDECREMENT_EXPR:
- case MODIFY_EXPR:
- case INIT_EXPR:
- case TARGET_EXPR:
- case CALL_EXPR:
- case TRY_CATCH_EXPR:
- case WITH_CLEANUP_EXPR:
- case EXIT_EXPR:
- case VA_ARG_EXPR:
- return false;
-
- case BIND_EXPR:
- /* For a binding, warn if no side effect within it. */
- exp = BIND_EXPR_BODY (exp);
- goto restart;
-
- case SAVE_EXPR:
- case NON_LVALUE_EXPR:
- case NOP_EXPR:
- exp = TREE_OPERAND (exp, 0);
- goto restart;
-
- case TRUTH_ORIF_EXPR:
- case TRUTH_ANDIF_EXPR:
- /* In && or ||, warn if 2nd operand has no side effect. */
- exp = TREE_OPERAND (exp, 1);
- goto restart;
-
- case COMPOUND_EXPR:
- if (warn_if_unused_value (TREE_OPERAND (exp, 0), locus))
- return true;
- /* Let people do `(foo (), 0)' without a warning. */
- if (TREE_CONSTANT (TREE_OPERAND (exp, 1)))
- return false;
- exp = TREE_OPERAND (exp, 1);
- goto restart;
-
- case COND_EXPR:
- /* If this is an expression with side effects, don't warn; this
- case commonly appears in macro expansions. */
- if (TREE_SIDE_EFFECTS (exp))
- return false;
- goto warn;
-
- case INDIRECT_REF:
- /* Don't warn about automatic dereferencing of references, since
- the user cannot control it. */
- if (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == REFERENCE_TYPE)
- {
- exp = TREE_OPERAND (exp, 0);
- goto restart;
- }
- /* Fall through. */
-
- default:
- /* Referencing a volatile value is a side effect, so don't warn. */
- if ((DECL_P (exp) || REFERENCE_CLASS_P (exp))
- && TREE_THIS_VOLATILE (exp))
- return false;
-
- /* If this is an expression which has no operands, there is no value
- to be unused. There are no such language-independent codes,
- but front ends may define such. */
- if (EXPRESSION_CLASS_P (exp) && TREE_OPERAND_LENGTH (exp) == 0)
- return false;
-
- warn:
- return warning_at (locus, OPT_Wunused_value, "value computed is not used");
- }
-}
-
-
-/* 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_set_subset_of (set2, set1)
- && !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;
- }
- }
- }
+ if (c_dialect_cxx ())
+ return c_fully_fold (x, /*for_init*/false, /*maybe_constp*/NULL);
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 about memset (&a, 0, sizeof (&a)); and similar mistakes with
- sizeof as last operand of certain builtins. */
-
-void
-sizeof_pointer_memaccess_warning (location_t *sizeof_arg_loc, tree callee,
- vec<tree, va_gc> *params, tree *sizeof_arg,
- bool (*comp_types) (tree, tree))
-{
- tree type, dest = NULL_TREE, src = NULL_TREE, tem;
- bool strop = false, cmp = false;
- unsigned int idx = ~0;
- location_t loc;
-
- if (TREE_CODE (callee) != FUNCTION_DECL
- || DECL_BUILT_IN_CLASS (callee) != BUILT_IN_NORMAL
- || vec_safe_length (params) <= 1)
- return;
-
- switch (DECL_FUNCTION_CODE (callee))
- {
- case BUILT_IN_STRNCMP:
- case BUILT_IN_STRNCASECMP:
- cmp = true;
- /* FALLTHRU */
- case BUILT_IN_STRNCPY:
- case BUILT_IN_STRNCPY_CHK:
- case BUILT_IN_STRNCAT:
- case BUILT_IN_STRNCAT_CHK:
- case BUILT_IN_STPNCPY:
- case BUILT_IN_STPNCPY_CHK:
- strop = true;
- /* FALLTHRU */
- case BUILT_IN_MEMCPY:
- case BUILT_IN_MEMCPY_CHK:
- case BUILT_IN_MEMMOVE:
- case BUILT_IN_MEMMOVE_CHK:
- if (params->length () < 3)
- return;
- src = (*params)[1];
- dest = (*params)[0];
- idx = 2;
- break;
- case BUILT_IN_BCOPY:
- if (params->length () < 3)
- return;
- src = (*params)[0];
- dest = (*params)[1];
- idx = 2;
- break;
- case BUILT_IN_MEMCMP:
- case BUILT_IN_BCMP:
- if (params->length () < 3)
- return;
- src = (*params)[1];
- dest = (*params)[0];
- idx = 2;
- cmp = true;
- break;
- case BUILT_IN_MEMSET:
- case BUILT_IN_MEMSET_CHK:
- if (params->length () < 3)
- return;
- dest = (*params)[0];
- idx = 2;
- break;
- case BUILT_IN_BZERO:
- dest = (*params)[0];
- idx = 1;
- break;
- case BUILT_IN_STRNDUP:
- src = (*params)[0];
- strop = true;
- idx = 1;
- break;
- case BUILT_IN_MEMCHR:
- if (params->length () < 3)
- return;
- src = (*params)[0];
- idx = 2;
- break;
- case BUILT_IN_SNPRINTF:
- case BUILT_IN_SNPRINTF_CHK:
- case BUILT_IN_VSNPRINTF:
- case BUILT_IN_VSNPRINTF_CHK:
- dest = (*params)[0];
- idx = 1;
- strop = true;
- break;
- default:
- break;
- }
-
- if (idx >= 3)
- return;
-
- if (sizeof_arg[idx] == NULL || sizeof_arg[idx] == error_mark_node)
- return;
-
- type = TYPE_P (sizeof_arg[idx])
- ? sizeof_arg[idx] : TREE_TYPE (sizeof_arg[idx]);
- if (!POINTER_TYPE_P (type))
- return;
-
- if (dest
- && (tem = tree_strip_nop_conversions (dest))
- && POINTER_TYPE_P (TREE_TYPE (tem))
- && comp_types (TREE_TYPE (TREE_TYPE (tem)), type))
- return;
-
- if (src
- && (tem = tree_strip_nop_conversions (src))
- && POINTER_TYPE_P (TREE_TYPE (tem))
- && comp_types (TREE_TYPE (TREE_TYPE (tem)), type))
- return;
-
- loc = sizeof_arg_loc[idx];
-
- if (dest && !cmp)
- {
- if (!TYPE_P (sizeof_arg[idx])
- && operand_equal_p (dest, sizeof_arg[idx], 0)
- && comp_types (TREE_TYPE (dest), type))
- {
- if (TREE_CODE (sizeof_arg[idx]) == ADDR_EXPR && !strop)
- warning_at (loc, OPT_Wsizeof_pointer_memaccess,
- "argument to %<sizeof%> in %qD call is the same "
- "expression as the destination; did you mean to "
- "remove the addressof?", callee);
- else if ((TYPE_PRECISION (TREE_TYPE (type))
- == TYPE_PRECISION (char_type_node))
- || strop)
- warning_at (loc, OPT_Wsizeof_pointer_memaccess,
- "argument to %<sizeof%> in %qD call is the same "
- "expression as the destination; did you mean to "
- "provide an explicit length?", callee);
- else
- warning_at (loc, OPT_Wsizeof_pointer_memaccess,
- "argument to %<sizeof%> in %qD call is the same "
- "expression as the destination; did you mean to "
- "dereference it?", callee);
- return;
- }
-
- if (POINTER_TYPE_P (TREE_TYPE (dest))
- && !strop
- && comp_types (TREE_TYPE (dest), type)
- && !VOID_TYPE_P (TREE_TYPE (type)))
- {
- warning_at (loc, OPT_Wsizeof_pointer_memaccess,
- "argument to %<sizeof%> in %qD call is the same "
- "pointer type %qT as the destination; expected %qT "
- "or an explicit length", callee, TREE_TYPE (dest),
- TREE_TYPE (TREE_TYPE (dest)));
- return;
- }
- }
-
- if (src && !cmp)
- {
- if (!TYPE_P (sizeof_arg[idx])
- && operand_equal_p (src, sizeof_arg[idx], 0)
- && comp_types (TREE_TYPE (src), type))
- {
- if (TREE_CODE (sizeof_arg[idx]) == ADDR_EXPR && !strop)
- warning_at (loc, OPT_Wsizeof_pointer_memaccess,
- "argument to %<sizeof%> in %qD call is the same "
- "expression as the source; did you mean to "
- "remove the addressof?", callee);
- else if ((TYPE_PRECISION (TREE_TYPE (type))
- == TYPE_PRECISION (char_type_node))
- || strop)
- warning_at (loc, OPT_Wsizeof_pointer_memaccess,
- "argument to %<sizeof%> in %qD call is the same "
- "expression as the source; did you mean to "
- "provide an explicit length?", callee);
- else
- warning_at (loc, OPT_Wsizeof_pointer_memaccess,
- "argument to %<sizeof%> in %qD call is the same "
- "expression as the source; did you mean to "
- "dereference it?", callee);
- return;
- }
-
- if (POINTER_TYPE_P (TREE_TYPE (src))
- && !strop
- && comp_types (TREE_TYPE (src), type)
- && !VOID_TYPE_P (TREE_TYPE (type)))
- {
- warning_at (loc, OPT_Wsizeof_pointer_memaccess,
- "argument to %<sizeof%> in %qD call is the same "
- "pointer type %qT as the source; expected %qT "
- "or an explicit length", callee, TREE_TYPE (src),
- TREE_TYPE (TREE_TYPE (src)));
- return;
- }
- }
-
- if (dest)
- {
- if (!TYPE_P (sizeof_arg[idx])
- && operand_equal_p (dest, sizeof_arg[idx], 0)
- && comp_types (TREE_TYPE (dest), type))
- {
- if (TREE_CODE (sizeof_arg[idx]) == ADDR_EXPR && !strop)
- warning_at (loc, OPT_Wsizeof_pointer_memaccess,
- "argument to %<sizeof%> in %qD call is the same "
- "expression as the first source; did you mean to "
- "remove the addressof?", callee);
- else if ((TYPE_PRECISION (TREE_TYPE (type))
- == TYPE_PRECISION (char_type_node))
- || strop)
- warning_at (loc, OPT_Wsizeof_pointer_memaccess,
- "argument to %<sizeof%> in %qD call is the same "
- "expression as the first source; did you mean to "
- "provide an explicit length?", callee);
- else
- warning_at (loc, OPT_Wsizeof_pointer_memaccess,
- "argument to %<sizeof%> in %qD call is the same "
- "expression as the first source; did you mean to "
- "dereference it?", callee);
- return;
- }
-
- if (POINTER_TYPE_P (TREE_TYPE (dest))
- && !strop
- && comp_types (TREE_TYPE (dest), type)
- && !VOID_TYPE_P (TREE_TYPE (type)))
- {
- warning_at (loc, OPT_Wsizeof_pointer_memaccess,
- "argument to %<sizeof%> in %qD call is the same "
- "pointer type %qT as the first source; expected %qT "
- "or an explicit length", callee, TREE_TYPE (dest),
- TREE_TYPE (TREE_TYPE (dest)));
- return;
- }
- }
-
- if (src)
- {
- if (!TYPE_P (sizeof_arg[idx])
- && operand_equal_p (src, sizeof_arg[idx], 0)
- && comp_types (TREE_TYPE (src), type))
- {
- if (TREE_CODE (sizeof_arg[idx]) == ADDR_EXPR && !strop)
- warning_at (loc, OPT_Wsizeof_pointer_memaccess,
- "argument to %<sizeof%> in %qD call is the same "
- "expression as the second source; did you mean to "
- "remove the addressof?", callee);
- else if ((TYPE_PRECISION (TREE_TYPE (type))
- == TYPE_PRECISION (char_type_node))
- || strop)
- warning_at (loc, OPT_Wsizeof_pointer_memaccess,
- "argument to %<sizeof%> in %qD call is the same "
- "expression as the second source; did you mean to "
- "provide an explicit length?", callee);
- else
- warning_at (loc, OPT_Wsizeof_pointer_memaccess,
- "argument to %<sizeof%> in %qD call is the same "
- "expression as the second source; did you mean to "
- "dereference it?", callee);
- return;
- }
-
- if (POINTER_TYPE_P (TREE_TYPE (src))
- && !strop
- && comp_types (TREE_TYPE (src), type)
- && !VOID_TYPE_P (TREE_TYPE (type)))
- {
- warning_at (loc, OPT_Wsizeof_pointer_memaccess,
- "argument to %<sizeof%> in %qD call is the same "
- "pointer type %qT as the second source; expected %qT "
- "or an explicit length", callee, TREE_TYPE (src),
- TREE_TYPE (TREE_TYPE (src)));
- return;
- }
- }
-
+ /* The C front-end has already folded X appropriately. */
+ return x;
}
-/* Warn for unlikely, improbable, or stupid DECL declarations
- of `main'. */
+/* Return true iff T is a boolean promoted to int. */
-void
-check_main_parameter_types (tree decl)
+bool
+bool_promoted_to_int_p (tree t)
{
- function_args_iterator iter;
- tree type;
- int argct = 0;
-
- FOREACH_FUNCTION_ARGS (TREE_TYPE (decl), type, iter)
- {
- /* XXX void_type_node belies the abstraction. */
- if (type == void_type_node || type == error_mark_node )
- break;
-
- tree t = type;
- if (TYPE_ATOMIC (t))
- pedwarn (input_location, OPT_Wmain,
- "%<_Atomic%>-qualified parameter type %qT of %q+D",
- type, decl);
- while (POINTER_TYPE_P (t))
- {
- t = TREE_TYPE (t);
- if (TYPE_ATOMIC (t))
- pedwarn (input_location, OPT_Wmain,
- "%<_Atomic%>-qualified parameter type %qT of %q+D",
- type, decl);
- }
-
- ++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);
-
- if (stdarg_p (TREE_TYPE (decl)))
- pedwarn (input_location, OPT_Wmain,
- "%q+D declared as variadic function", decl);
+ return (CONVERT_EXPR_P (t)
+ && TREE_TYPE (t) == integer_type_node
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) == BOOLEAN_TYPE);
}
/* vector_targets_convertible_p is used for vector pointer types. The
@@ -2135,7 +1069,7 @@ c_build_vec_perm_expr (location_t loc, tree v0, tree v1, tree mask,
/* Like tree.c:get_narrower, but retain conversion from C++0x scoped enum
to integral type. */
-static tree
+tree
c_common_get_narrower (tree op, int *unsignedp_ptr)
{
op = get_narrower (op, unsignedp_ptr);
@@ -2564,143 +1498,6 @@ unsafe_conversion_p (location_t loc, tree type, tree expr, bool produce_warns)
return give_warning;
}
-/* 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 (location_t loc, tree type, tree expr)
-{
- tree expr_type = TREE_TYPE (expr);
- enum conversion_safety conversion_kind;
-
- if (!warn_conversion && !warn_sign_conversion && !warn_float_conversion)
- return;
-
- /* This may happen, because for LHS op= RHS we preevaluate
- RHS and create C_MAYBE_CONST_EXPR <SAVE_EXPR <RHS>>, which
- means we could no longer see the code of the EXPR. */
- if (TREE_CODE (expr) == C_MAYBE_CONST_EXPR)
- expr = C_MAYBE_CONST_EXPR_EXPR (expr);
- if (TREE_CODE (expr) == SAVE_EXPR)
- expr = TREE_OPERAND (expr, 0);
-
- 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:
- case COMPLEX_CST:
- conversion_kind = unsafe_conversion_p (loc, type, expr, true);
- if (conversion_kind == UNSAFE_REAL)
- warning_at (loc, OPT_Wfloat_conversion,
- "conversion to %qT alters %qT constant value",
- type, expr_type);
- else if (conversion_kind)
- warning_at (loc, OPT_Wconversion,
- "conversion to %qT alters %qT constant value",
- type, expr_type);
- return;
-
- case COND_EXPR:
- {
- /* In case of COND_EXPR, 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);
-
- conversion_warning (loc, type, op1);
- conversion_warning (loc, type, op2);
- return;
- }
-
- default: /* 'expr' is not a constant. */
- conversion_kind = unsafe_conversion_p (loc, type, expr, true);
- if (conversion_kind == UNSAFE_REAL)
- warning_at (loc, OPT_Wfloat_conversion,
- "conversion to %qT from %qT may alter its value",
- type, expr_type);
- else if (conversion_kind == UNSAFE_IMAGINARY)
- warning_at (loc, OPT_Wconversion,
- "conversion to %qT from %qT discards imaginary component",
- type, expr_type);
- else if (conversion_kind)
- 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 (location_t loc, tree type, tree expr,
- tree result)
-{
- loc = expansion_point_location_if_in_system_header (loc);
-
- 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_at (loc, OPT_Woverflow,
- "large integer implicitly truncated to unsigned type");
- else
- conversion_warning (loc, type, expr);
- }
- else if (!int_fits_type_p (expr, c_common_unsigned_type (type)))
- warning_at (loc, 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_at (loc, OPT_Woverflow,
- "overflow in implicit constant conversion");
-
- else
- conversion_warning (loc, type, expr);
- }
- else if ((TREE_CODE (result) == INTEGER_CST
- || TREE_CODE (result) == FIXED_CST) && TREE_OVERFLOW (result))
- warning_at (loc, OPT_Woverflow,
- "overflow in implicit constant conversion");
- else
- conversion_warning (loc, type, expr);
-}
-
/* Convert EXPR to TYPE, warning about conversion problems with constants.
Invoke this function on every expression that is converted implicitly,
@@ -2773,7 +1570,7 @@ 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 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);
@@ -2892,32 +1689,33 @@ warn_for_collisions (struct tlist *list)
/* Return nonzero if X is a tree that can be verified by the sequence point
warnings. */
-static int
+
+static bool
warning_candidate_p (tree x)
{
if (DECL_P (x) && DECL_ARTIFICIAL (x))
- return 0;
+ return false;
if (TREE_CODE (x) == BLOCK)
- return 0;
+ return false;
/* 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;
+ return false;
if (!lvalue_p (x))
- return 0;
+ return false;
/* 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;
+ return false;
if (TREE_CODE (x) == STRING_CST)
- return 0;
+ return false;
- return 1;
+ return true;
}
/* Return nonzero if X and Y appear to be the same candidate (or NULL) */
@@ -2981,13 +1779,15 @@ verify_tree (tree x, struct tlist **pbefore_sp, struct tlist **pno_sp,
case COMPOUND_EXPR:
case TRUTH_ANDIF_EXPR:
case TRUTH_ORIF_EXPR:
- tmp_before = tmp_nosp = tmp_list3 = 0;
+ tmp_before = tmp_nosp = tmp_list2 = 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);
+ verify_tree (TREE_OPERAND (x, 1), &tmp_list3, &tmp_list2, NULL_TREE);
+ warn_for_collisions (tmp_list2);
merge_tlist (pbefore_sp, tmp_list3, 0);
+ merge_tlist (pno_sp, tmp_list2, 0);
return;
case COND_EXPR:
@@ -3379,10 +2179,6 @@ c_common_type_for_mode (machine_mode mode, int unsignedp)
return (unsignedp ? int_n_trees[i].unsigned_type
: int_n_trees[i].signed_type);
- 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;
@@ -3409,6 +2205,11 @@ c_common_type_for_mode (machine_mode mode, int unsignedp)
if (mode == TYPE_MODE (long_double_type_node))
return long_double_type_node;
+ for (i = 0; i < NUM_FLOATN_NX_TYPES; i++)
+ if (FLOATN_NX_TYPE_NODE (i) != NULL_TREE
+ && mode == TYPE_MODE (FLOATN_NX_TYPE_NODE (i)))
+ return FLOATN_NX_TYPE_NODE (i);
+
if (mode == TYPE_MODE (void_type_node))
return void_type_node;
@@ -3434,6 +2235,11 @@ c_common_type_for_mode (machine_mode mode, int unsignedp)
if (mode == TYPE_MODE (complex_long_double_type_node))
return complex_long_double_type_node;
+ for (i = 0; i < NUM_FLOATN_NX_TYPES; i++)
+ if (COMPLEX_FLOATN_NX_TYPE_NODE (i) != NULL_TREE
+ && mode == TYPE_MODE (COMPLEX_FLOATN_NX_TYPE_NODE (i)))
+ return COMPLEX_FLOATN_NX_TYPE_NODE (i);
+
if (mode == TYPE_MODE (complex_integer_type_node) && !unsignedp)
return complex_integer_type_node;
@@ -3602,8 +2408,6 @@ c_common_signed_or_unsigned_type (int unsignedp, tree type)
return (unsignedp ? int_n_trees[i].unsigned_type
: int_n_trees[i].signed_type);
- 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;
@@ -3724,10 +2528,6 @@ c_common_signed_or_unsigned_type (int unsignedp, tree type)
return (unsignedp ? int_n_trees[i].unsigned_type
: int_n_trees[i].signed_type);
- 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;
@@ -4013,10 +2813,9 @@ shorten_compare (location_t loc, tree *op0_ptr, tree *op1_ptr,
/* Convert primop1 to target type, but do not introduce
additional overflow. We know primop1 is an int_cst. */
primop1 = force_fit_type (*restype_ptr,
- wide_int::from
- (primop1,
- TYPE_PRECISION (*restype_ptr),
- TYPE_SIGN (TREE_TYPE (primop1))),
+ wi::to_wide
+ (primop1,
+ TYPE_PRECISION (*restype_ptr)),
0, TREE_OVERFLOW (primop1));
}
if (type != *restype_ptr)
@@ -4271,7 +3070,7 @@ pointer_int_sum (location_t loc, enum tree_code resultcode,
size_exp = integer_one_node;
}
else
- size_exp = size_in_bytes (TREE_TYPE (result_type));
+ size_exp = size_in_bytes_loc (loc, 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
@@ -4451,6 +3250,11 @@ c_common_truthvalue_conversion (location_t location, tree expr)
return expr;
case INTEGER_CST:
+ if (TREE_CODE (TREE_TYPE (expr)) == ENUMERAL_TYPE
+ && !integer_zerop (expr)
+ && !integer_onep (expr))
+ warning_at (location, OPT_Wint_in_bool_context,
+ "enum constant in boolean context");
return integer_zerop (expr) ? truthvalue_false_node
: truthvalue_true_node;
@@ -4466,7 +3270,7 @@ c_common_truthvalue_conversion (location_t location, tree expr)
: truthvalue_false_node;
case FUNCTION_DECL:
- expr = build_unary_op (location, ADDR_EXPR, expr, 0);
+ expr = build_unary_op (location, ADDR_EXPR, expr, false);
/* Fall through. */
case ADDR_EXPR:
@@ -4518,23 +3322,55 @@ c_common_truthvalue_conversion (location_t location, tree expr)
return c_common_truthvalue_conversion (location,
TREE_OPERAND (expr, 0));
+ case MULT_EXPR:
+ warning_at (EXPR_LOCATION (expr), OPT_Wint_in_bool_context,
+ "%<*%> in boolean context, suggest %<&&%> instead");
+ break;
+
+ case LSHIFT_EXPR:
+ /* We will only warn on signed shifts here, because the majority of
+ false positive warnings happen in code where unsigned arithmetic
+ was used in anticipation of a possible overflow.
+ Furthermore, if we see an unsigned type here we know that the
+ result of the shift is not subject to integer promotion rules. */
+ if (TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE
+ && !TYPE_UNSIGNED (TREE_TYPE (expr)))
+ warning_at (EXPR_LOCATION (expr), OPT_Wint_in_bool_context,
+ "%<<<%> in boolean context, did you mean %<<%> ?");
+ break;
+
case COND_EXPR:
+ if (warn_int_in_bool_context
+ && !from_macro_definition_at (EXPR_LOCATION (expr)))
+ {
+ tree val1 = fold_for_warn (TREE_OPERAND (expr, 1));
+ tree val2 = fold_for_warn (TREE_OPERAND (expr, 2));
+ if (TREE_CODE (val1) == INTEGER_CST
+ && TREE_CODE (val2) == INTEGER_CST
+ && !integer_zerop (val1)
+ && !integer_zerop (val2)
+ && (!integer_onep (val1)
+ || !integer_onep (val2)))
+ warning_at (EXPR_LOCATION (expr), OPT_Wint_in_bool_context,
+ "?: using integer constants in boolean context, "
+ "the expression will always evaluate to %<true%>");
+ else if ((TREE_CODE (val1) == INTEGER_CST
+ && !integer_zerop (val1)
+ && !integer_onep (val1))
+ || (TREE_CODE (val2) == INTEGER_CST
+ && !integer_zerop (val2)
+ && !integer_onep (val2)))
+ warning_at (EXPR_LOCATION (expr), OPT_Wint_in_bool_context,
+ "?: using integer constants in boolean context");
+ }
/* 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;
- }
+ /* Avoid premature folding. */
+ break;
else
{
+ int w = warn_int_in_bool_context;
+ warn_int_in_bool_context = 0;
/* Folding will happen later for C. */
expr = build3 (COND_EXPR, truthvalue_type_node,
TREE_OPERAND (expr, 0),
@@ -4542,6 +3378,7 @@ c_common_truthvalue_conversion (location_t location, tree expr)
TREE_OPERAND (expr, 1)),
c_common_truthvalue_conversion (location,
TREE_OPERAND (expr, 2)));
+ warn_int_in_bool_context = w;
goto ret;
}
@@ -4551,6 +3388,7 @@ c_common_truthvalue_conversion (location_t location, tree expr)
tree fromtype = TREE_TYPE (TREE_OPERAND (expr, 0));
if (POINTER_TYPE_P (totype)
+ && !c_inhibit_evaluation_warnings
&& TREE_CODE (fromtype) == REFERENCE_TYPE)
{
tree inner = expr;
@@ -4585,8 +3423,9 @@ c_common_truthvalue_conversion (location_t location, tree expr)
if (!TREE_NO_WARNING (expr)
&& warn_parentheses)
{
- warning (OPT_Wparentheses,
- "suggest parentheses around assignment used as truth value");
+ warning_at (location, OPT_Wparentheses,
+ "suggest parentheses around assignment used as "
+ "truth value");
TREE_NO_WARNING (expr) = 1;
}
break;
@@ -4604,10 +3443,10 @@ c_common_truthvalue_conversion (location_t location, tree expr)
? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR),
c_common_truthvalue_conversion
(location,
- build_unary_op (location, REALPART_EXPR, t, 0)),
+ build_unary_op (location, REALPART_EXPR, t, false)),
c_common_truthvalue_conversion
(location,
- build_unary_op (location, IMAGPART_EXPR, t, 0)),
+ build_unary_op (location, IMAGPART_EXPR, t, false)),
0));
goto ret;
}
@@ -4736,8 +3575,6 @@ static GTY(()) hash_table<c_type_hasher> *type_hash_table;
alias_set_type
c_common_get_alias_set (tree t)
{
- tree u;
-
/* 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))
@@ -4747,19 +3584,6 @@ c_common_get_alias_set (tree 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;
@@ -5330,17 +4154,16 @@ c_common_nodes_and_builtins (void)
#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));
+ if (targetm.scalar_mode_supported_p (TImode))
+ {
+ widest_integer_literal_type_node = intTI_type_node;
+ widest_unsigned_literal_type_node = unsigned_intTI_type_node;
+ }
+ else
+ {
+ widest_integer_literal_type_node = intDI_type_node;
+ widest_unsigned_literal_type_node = unsigned_intDI_type_node;
+ }
signed_size_type_node = c_common_signed_type (size_type_node);
@@ -5351,6 +4174,12 @@ c_common_nodes_and_builtins (void)
record_builtin_type (RID_DOUBLE, NULL, double_type_node);
record_builtin_type (RID_MAX, "long double", long_double_type_node);
+ if (!c_dialect_cxx ())
+ for (i = 0; i < NUM_FLOATN_NX_TYPES; i++)
+ if (FLOATN_NX_TYPE_NODE (i) != NULL_TREE)
+ record_builtin_type ((enum rid) (RID_FLOATN_NX_FIRST + i), NULL,
+ FLOATN_NX_TYPE_NODE (i));
+
/* Only supported decimal floating point extension if the target
actually supports underlying modes. */
if (targetm.scalar_mode_supported_p (SDmode)
@@ -5440,10 +4269,28 @@ c_common_nodes_and_builtins (void)
TYPE_DECL, get_identifier ("complex long double"),
complex_long_double_type_node));
+ if (!c_dialect_cxx ())
+ for (i = 0; i < NUM_FLOATN_NX_TYPES; i++)
+ if (COMPLEX_FLOATN_NX_TYPE_NODE (i) != NULL_TREE)
+ {
+ char buf[30];
+ sprintf (buf, "complex _Float%d%s", floatn_nx_types[i].n,
+ floatn_nx_types[i].extended ? "x" : "");
+ lang_hooks.decls.pushdecl
+ (build_decl (UNKNOWN_LOCATION,
+ TYPE_DECL,
+ get_identifier (buf),
+ COMPLEX_FLOATN_NX_TYPE_NODE (i)));
+ }
+
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);
+ {
+ /* 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);
+ /* Likewise for const struct tm*. */
+ const_tm_ptr_type_node = build_variant_type_copy (const_ptr_type_node);
+ }
record_builtin_type (RID_VOID, NULL, void_type_node);
@@ -5619,8 +4466,6 @@ c_common_nodes_and_builtins (void)
default_function_type
= build_varargs_function_type_list (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
@@ -5702,36 +4547,30 @@ build_va_arg (location_t loc, tree expr, tree type)
{
tree va_type = TREE_TYPE (expr);
tree canon_va_type = (va_type == error_mark_node
- ? NULL_TREE
+ ? error_mark_node
: targetm.canonical_va_list_type (va_type));
if (va_type == error_mark_node
|| canon_va_type == NULL_TREE)
{
+ if (canon_va_type == NULL_TREE)
+ error_at (loc, "first argument to %<va_arg%> not of type %<va_list%>");
+
/* Let's handle things neutrallly, if expr:
- has undeclared type, or
- is not an va_list type. */
- return build_va_arg_1 (loc, type, expr);
+ return build_va_arg_1 (loc, type, error_mark_node);
}
if (TREE_CODE (canon_va_type) != ARRAY_TYPE)
{
/* Case 1: Not an array type. */
- /* Take the address, to get '&ap'. */
+ /* Take the address, to get '&ap'. Note that &ap is not a va_list
+ type. */
mark_addressable (expr);
expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (expr)), expr);
- /* Verify that &ap is still recognized as having va_list type. */
- tree canon_expr_type
- = targetm.canonical_va_list_type (TREE_TYPE (expr));
- if (canon_expr_type == NULL_TREE)
- {
- error_at (loc,
- "first argument to %<va_arg%> not of type %<va_list%>");
- return error_mark_node;
- }
-
return build_va_arg_1 (loc, type, expr);
}
@@ -5798,18 +4637,16 @@ build_va_arg (location_t loc, tree expr, tree type)
/* Verify that &ap is still recognized as having va_list type. */
tree canon_expr_type
= targetm.canonical_va_list_type (TREE_TYPE (expr));
- if (canon_expr_type == NULL_TREE)
- {
- error_at (loc,
- "first argument to %<va_arg%> not of type %<va_list%>");
- return error_mark_node;
- }
+ gcc_assert (canon_expr_type != NULL_TREE);
}
else
{
/* Case 2b: va_list is pointer to array elem type. */
gcc_assert (POINTER_TYPE_P (va_type));
- gcc_assert (TREE_TYPE (va_type) == TREE_TYPE (canon_va_type));
+
+ /* Comparison as in std_canonical_va_list_type. */
+ gcc_assert (TYPE_MAIN_VARIANT (TREE_TYPE (va_type))
+ == TYPE_MAIN_VARIANT (TREE_TYPE (canon_va_type)));
/* Don't take the address. We've already got '&ap'. */
;
@@ -6124,19 +4961,19 @@ c_add_case_label (location_t loc, splay_tree cases, tree cond, tree orig_type,
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");
+ inform (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");
+ inform (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");
+ inform (DECL_SOURCE_LOCATION (duplicate),
+ "this is the first default label");
}
goto error_out;
}
@@ -6162,224 +4999,6 @@ c_add_case_label (location_t loc, splay_tree cases, tree cond, tree orig_type,
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[WIDE_INT_PRINT_BUFFER_SIZE];
-
- if (tree_fits_uhwi_p (key))
- print_dec (key, buf, UNSIGNED);
- else if (tree_fits_shwi_p (key))
- print_dec (key, buf, SIGNED);
- else
- print_hex (key, buf);
-
- 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, bool bool_cond_p,
- bool outside_range_p)
-{
- splay_tree_node default_node;
- splay_tree_node node;
- tree chain;
-
- if (!warn_switch && !warn_switch_enum && !warn_switch_default
- && !warn_switch_bool)
- 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");
-
- /* There are certain cases where -Wswitch-bool warnings aren't
- desirable, such as
- switch (boolean)
- {
- case true: ...
- case false: ...
- }
- so be careful here. */
- if (warn_switch_bool && bool_cond_p)
- {
- splay_tree_node min_node;
- /* If there's a default node, it's also the value with the minimal
- key. So look at the penultimate key (if any). */
- if (default_node)
- min_node = splay_tree_successor (cases, (splay_tree_key) NULL);
- else
- min_node = splay_tree_min (cases);
- tree min = min_node ? (tree) min_node->key : NULL_TREE;
-
- splay_tree_node max_node = splay_tree_max (cases);
- /* This might be a case range, so look at the value with the
- maximal key and then check CASE_HIGH. */
- tree max = max_node ? (tree) max_node->value : NULL_TREE;
- if (max)
- max = CASE_HIGH (max) ? CASE_HIGH (max) : CASE_LOW (max);
-
- /* If there's a case value > 1 or < 0, that is outside bool
- range, warn. */
- if (outside_range_p
- || (max && wi::gts_p (max, 1))
- || (min && wi::lts_p (min, 0))
- /* And handle the
- switch (boolean)
- {
- case true: ...
- case false: ...
- default: ...
- }
- case, where we want to warn. */
- || (default_node
- && max && wi::eq_p (max, 1)
- && min && wi::eq_p (min, 0)))
- warning_at (switch_location, OPT_Wswitch_bool,
- "switch condition has boolean value");
- }
-
- /* From here on, we only care 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.
@@ -6544,1129 +5163,6 @@ c_init_attributes (void)
#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 (VAR_P (*node))
- 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 (VAR_P (*node))
- 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_qualified_type
- (build_pointer_type
- (build_type_variant (TREE_TYPE (type),
- TYPE_READONLY (TREE_TYPE (type)), 1)),
- TYPE_QUALS (type)));
- 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
- || TREE_CODE (*node) == LABEL_DECL)
- {
- if (lookup_attribute ("cold", DECL_ATTRIBUTES (*node)) != NULL)
- {
- warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
- "with attribute %qs", 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
- || TREE_CODE (*node) == LABEL_DECL)
- {
- if (lookup_attribute ("hot", DECL_ATTRIBUTES (*node)) != NULL)
- {
- warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
- "with attribute %qs", 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 "no_sanitize_address" attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_no_sanitize_address_attribute (tree *node, tree name, tree, int,
- 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 "no_address_safety_analysis" attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_no_address_safety_analysis_attribute (tree *node, tree name, tree, int,
- bool *no_add_attrs)
-{
- if (TREE_CODE (*node) != FUNCTION_DECL)
- warning (OPT_Wattributes, "%qE attribute ignored", name);
- else if (!lookup_attribute ("no_sanitize_address", DECL_ATTRIBUTES (*node)))
- DECL_ATTRIBUTES (*node)
- = tree_cons (get_identifier ("no_sanitize_address"),
- NULL_TREE, DECL_ATTRIBUTES (*node));
- *no_add_attrs = true;
- return NULL_TREE;
-}
-
-/* Handle a "no_sanitize_undefined" attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_no_sanitize_undefined_attribute (tree *node, tree name, tree, int,
- 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 "stack_protect" attribute; arguments as in
- struct attribute_spec.handler. */
-static tree
-handle_stack_protect_attribute (tree *node, tree name, tree, int,
- bool *no_add_attrs)
-{
- if (TREE_CODE (*node) != FUNCTION_DECL)
- {
- warning (OPT_Wattributes, "%qE attribute ignored", name);
- *no_add_attrs = true;
- }
- else
- DECL_ATTRIBUTES (*node)
- = tree_cons (get_identifier ("stack_protect"),
- NULL_TREE, DECL_ATTRIBUTES (*node));
-
- 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)
- {
- if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (*node)))
- {
- warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
- "with attribute %qs", name, "always_inline");
- *no_add_attrs = true;
- }
- else
- 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 "no_icf" attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_noicf_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)
- {
- if (lookup_attribute ("noinline", DECL_ATTRIBUTES (*node)))
- {
- warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
- "with %qs attribute", name, "noinline");
- *no_add_attrs = true;
- }
- else if (lookup_attribute ("target_clones", DECL_ATTRIBUTES (*node)))
- {
- warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
- "with %qs attribute", name, "target_clones");
- *no_add_attrs = true;
- }
- else
- /* 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
- || (VAR_P (node) && TREE_STATIC (node))
- || (TREE_CODE (node) == TYPE_DECL))
- {
- TREE_USED (node) = 1;
- DECL_PRESERVE_P (node) = 1;
- if (VAR_P (node))
- 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
- || VAR_OR_FUNCTION_DECL_P (decl)
- || TREE_CODE (decl) == LABEL_DECL
- || TREE_CODE (decl) == TYPE_DECL)
- {
- TREE_USED (decl) = 1;
- if (VAR_P (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 (VAR_OR_FUNCTION_DECL_P (node))
- {
- 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 the "no_reorder" attribute. Arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_no_reorder_attribute (tree *pnode,
- tree name,
- tree,
- int,
- bool *no_add_attrs)
-{
- tree node = *pnode;
-
- if (!VAR_OR_FUNCTION_DECL_P (node)
- && !(TREE_STATIC (node) || DECL_EXTERNAL (node)))
- {
- warning (OPT_Wattributes,
- "%qE attribute only affects top level objects",
- 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_qualified_type
- (build_pointer_type
- (build_type_variant (TREE_TYPE (type), 1,
- TREE_THIS_VOLATILE (TREE_TYPE (type)))),
- TYPE_QUALS (type)));
- else
- {
- warning (OPT_Wattributes, "%qE attribute ignored", name);
- *no_add_attrs = true;
- }
-
- return NULL_TREE;
-}
-
-/* Handle a "scalar_storage_order" attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_scalar_storage_order_attribute (tree *node, tree name, tree args,
- int flags, bool *no_add_attrs)
-{
- tree id = TREE_VALUE (args);
- tree type;
-
- if (TREE_CODE (*node) == TYPE_DECL
- && ! (flags & ATTR_FLAG_CXX11))
- node = &TREE_TYPE (*node);
- type = *node;
-
- if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN)
- {
- error ("scalar_storage_order is not supported because endianness "
- "is not uniform");
- return NULL_TREE;
- }
-
- if (RECORD_OR_UNION_TYPE_P (type) && !c_dialect_cxx ())
- {
- bool reverse = false;
-
- if (TREE_CODE (id) == STRING_CST
- && strcmp (TREE_STRING_POINTER (id), "big-endian") == 0)
- reverse = !BYTES_BIG_ENDIAN;
- else if (TREE_CODE (id) == STRING_CST
- && strcmp (TREE_STRING_POINTER (id), "little-endian") == 0)
- reverse = BYTES_BIG_ENDIAN;
- else
- {
- error ("scalar_storage_order argument must be one of \"big-endian\""
- " or \"little-endian\"");
- return NULL_TREE;
- }
-
- if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
- {
- if (reverse)
- /* A type variant isn't good enough, since we don't want a cast
- to such a type to be removed as a no-op. */
- *node = type = build_duplicate_type (type);
- }
-
- TYPE_REVERSE_STORAGE_ORDER (type) = reverse;
- return NULL_TREE;
- }
-
- 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
- && ! (flags & ATTR_FLAG_CXX11))
- node = &TREE_TYPE (*node);
- type = *node;
-
- if (TREE_CODE (type) == UNION_TYPE)
- {
- /* Make sure that the first field will work for a transparent union.
- If the type isn't complete yet, leave the check to the code in
- finish_struct. */
- if (TYPE_SIZE (type))
- {
- tree first = first_field (type);
- if (first == NULL_TREE
- || DECL_ARTIFICIAL (first)
- || TYPE_MODE (type) != DECL_MODE (first))
- goto ignored;
- }
-
- if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
- {
- /* If the type isn't complete yet, setting the flag
- on a variant wouldn't ever be checked. */
- if (!TYPE_SIZE (type))
- goto ignored;
-
- /* build_duplicate_type doesn't work for C++. */
- if (c_dialect_cxx ())
- goto ignored;
-
- /* A type variant isn't good enough, since we don't want a cast
- to such a type to be removed as a no-op. */
- *node = type = build_duplicate_type (type);
- }
-
- for (tree t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
- TYPE_TRANSPARENT_AGGR (t) = 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 (TREE_CODE (arg) == IDENTIFIER_NODE)
- goto invalid;
- if (arg == error_mark_node)
- return DEFAULT_INIT_PRIORITY;
- arg = default_conversion (arg);
- if (!tree_fits_shwi_p (arg)
- || !INTEGRAL_TYPE_P (TREE_TYPE (arg)))
- goto invalid;
-
- pri = tree_to_shwi (arg);
- 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 (machine_mode mode)
-{
- enum mode_class mclass = GET_MODE_CLASS (mode);
- 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);
- 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 = (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, 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_common.have_named_sections)
- {
- error_at (DECL_SOURCE_LOCATION (*node),
- "section attributes are not supported for this target");
- goto fail;
- }
-
- user_defined_section_attribute = true;
-
- if (!VAR_OR_FUNCTION_DECL_P (decl))
- {
- error ("section attribute not allowed for %q+D", *node);
- goto fail;
- }
-
- if (TREE_CODE (TREE_VALUE (args)) != STRING_CST)
- {
- error ("section attribute argument not a string constant");
- goto fail;
- }
-
- if (VAR_P (decl)
- && current_function_decl != NULL_TREE
- && !TREE_STATIC (decl))
- {
- error_at (DECL_SOURCE_LOCATION (decl),
- "section attribute cannot be specified for local variables");
- goto fail;
- }
-
- /* The decl may have already been given a section attribute
- from a previous declaration. Ensure they match. */
- if (DECL_SECTION_NAME (decl) != NULL
- && strcmp (DECL_SECTION_NAME (decl),
- TREE_STRING_POINTER (TREE_VALUE (args))) != 0)
- {
- error ("section of %q+D conflicts with previous declaration", *node);
- goto fail;
- }
-
- if (VAR_P (decl)
- && !targetm.have_tls && targetm.emutls.tmpl_section
- && DECL_THREAD_LOCAL_P (decl))
- {
- error ("section of %q+D cannot be overridden", *node);
- goto fail;
- }
-
- set_decl_section_name (decl, TREE_STRING_POINTER (TREE_VALUE (args)));
- return NULL_TREE;
-
-fail:
- *no_add_attrs = true;
- return NULL_TREE;
-}
-
/* Check whether ALIGN is a valid user-specified alignment. If so,
return its base-2 log; if not, output an error and return -1. If
ALLOW_ZERO then 0 is valid and should result in a return of -1 with
@@ -7692,7 +5188,7 @@ check_user_alignment (const_tree align, bool allow_zero)
error ("requested alignment is not a positive power of 2");
return -1;
}
- else if (i >= HOST_BITS_PER_INT - BITS_PER_UNIT_LOG)
+ else if (i >= HOST_BITS_PER_INT - LOG2_BITS_PER_UNIT)
{
error ("requested alignment is too large");
return -1;
@@ -7700,502 +5196,6 @@ check_user_alignment (const_tree align, bool allow_zero)
return i;
}
-/*
- If in c++-11, check if the c++-11 alignment constraint with respect
- to fundamental alignment (in [dcl.align]) are satisfied. If not in
- c++-11 mode, does nothing.
-
- [dcl.align]2/ says:
-
- [* if the constant expression evaluates to a fundamental alignment,
- the alignment requirement of the declared entity shall be the
- specified fundamental alignment.
-
- * if the constant expression evaluates to an extended alignment
- and the implementation supports that alignment in the context
- of the declaration, the alignment of the declared entity shall
- be that alignment
-
- * if the constant expression evaluates to an extended alignment
- and the implementation does not support that alignment in the
- context of the declaration, the program is ill-formed]. */
-
-static bool
-check_cxx_fundamental_alignment_constraints (tree node,
- unsigned align_log,
- int flags)
-{
- bool alignment_too_large_p = false;
- unsigned requested_alignment = 1U << align_log;
- unsigned max_align = 0;
-
- if ((!(flags & ATTR_FLAG_CXX11) && !warn_cxx_compat)
- || (node == NULL_TREE || node == error_mark_node))
- return true;
-
- if (cxx_fundamental_alignment_p (requested_alignment))
- return true;
-
- if (DECL_P (node))
- {
- if (TREE_STATIC (node))
- {
- /* For file scope variables and static members, the target
- supports alignments that are at most
- MAX_OFILE_ALIGNMENT. */
- if (requested_alignment > (max_align = MAX_OFILE_ALIGNMENT))
- alignment_too_large_p = true;
- }
- else
- {
-#ifdef BIGGEST_FIELD_ALIGNMENT
-#define MAX_TARGET_FIELD_ALIGNMENT BIGGEST_FIELD_ALIGNMENT
-#else
-#define MAX_TARGET_FIELD_ALIGNMENT BIGGEST_ALIGNMENT
-#endif
- /* For non-static members, the target supports either
- alignments that at most either BIGGEST_FIELD_ALIGNMENT
- if it is defined or BIGGEST_ALIGNMENT. */
- max_align = MAX_TARGET_FIELD_ALIGNMENT;
- if (TREE_CODE (node) == FIELD_DECL
- && requested_alignment > (max_align = MAX_TARGET_FIELD_ALIGNMENT))
- alignment_too_large_p = true;
-#undef MAX_TARGET_FIELD_ALIGNMENT
- /* For stack variables, the target supports at most
- MAX_STACK_ALIGNMENT. */
- else if (decl_function_context (node) != NULL
- && requested_alignment > (max_align = MAX_STACK_ALIGNMENT))
- alignment_too_large_p = true;
- }
- }
- else if (TYPE_P (node))
- {
- /* Let's be liberal for types. */
- if (requested_alignment > (max_align = BIGGEST_ALIGNMENT))
- alignment_too_large_p = true;
- }
-
- if (alignment_too_large_p)
- pedwarn (input_location, OPT_Wattributes,
- "requested alignment %d is larger than %d",
- requested_alignment, max_align);
-
- return !alignment_too_large_p;
-}
-
-/* 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;
- int i;
-
- if (args)
- {
- align_expr = TREE_VALUE (args);
- if (align_expr && TREE_CODE (align_expr) != IDENTIFIER_NODE
- && TREE_CODE (align_expr) != FUNCTION_DECL)
- align_expr = default_conversion (align_expr);
- }
- else
- align_expr = size_int (ATTRIBUTE_ALIGNED_VALUE / BITS_PER_UNIT);
-
- 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 ((i = check_user_alignment (align_expr, false)) == -1
- || !check_cxx_fundamental_alignment_constraints (*node, i, flags))
- *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 (DECL_USER_ALIGN (decl)
- && DECL_ALIGN (decl) > (1U << i) * BITS_PER_UNIT)
- /* C++-11 [dcl.align/4]:
-
- When multiple alignment-specifiers are specified for an
- entity, the alignment requirement shall be set to the
- strictest specified alignment.
-
- This formally comes from the c++11 specification but we are
- doing it for the GNU attribute syntax as well. */
- *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 (VAR_OR_FUNCTION_DECL_P (*node))
- declare_weak (*node);
- else
- warning (OPT_Wattributes, "%qE attribute ignored", name);
-
- return NULL_TREE;
-}
-
-/* Handle a "noplt" attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_noplt_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)
- {
- warning (OPT_Wattributes,
- "%qE attribute is only applicable on functions", name);
- *no_add_attrs = true;
- return NULL_TREE;
- }
- 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 || !VAR_P (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
- 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;
- }
-
- if (decl_in_symtab_p (*node))
- {
- struct symtab_node *n = symtab_node::get (decl);
- if (n && n->refuse_visibility_changes)
- {
- if (is_alias)
- error ("%+D declared alias after being used", decl);
- else
- error ("%+D declared ifunc after being used", decl);
- }
- }
-
-
- 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
- || !VAR_OR_FUNCTION_DECL_P (*node))
- {
- 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;
- }
-
- if (decl_in_symtab_p (*node))
- {
- struct symtab_node *n = symtab_node::get (*node);
- if (n && n->refuse_visibility_changes)
- error ("%+D declared weakref after being used", *node);
- }
-
- 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 (!RECORD_OR_UNION_TYPE_P (*node))
- {
- 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.
@@ -8241,876 +5241,21 @@ c_determine_visibility (tree 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 (!VAR_P (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\"");
-
- set_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
- 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 (position && TREE_CODE (position) != IDENTIFIER_NODE
- && TREE_CODE (position) != FUNCTION_DECL)
- position = default_conversion (position);
-
- if (!tree_fits_uhwi_p (position)
- || !arg_count
- || !IN_RANGE (tree_to_uhwi (position), 1, arg_count))
- {
- warning (OPT_Wattributes,
- "alloc_size parameter outside range");
- *no_add_attrs = true;
- return NULL_TREE;
- }
- }
- return NULL_TREE;
-}
-
-/* Handle a "alloc_align" attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_alloc_align_attribute (tree *node, tree, tree args, int,
- bool *no_add_attrs)
-{
- unsigned arg_count = type_num_arguments (*node);
- tree position = TREE_VALUE (args);
- if (position && TREE_CODE (position) != IDENTIFIER_NODE)
- position = default_conversion (position);
-
- if (!tree_fits_uhwi_p (position)
- || !arg_count
- || !IN_RANGE (tree_to_uhwi (position), 1, arg_count))
- {
- warning (OPT_Wattributes,
- "alloc_align parameter outside range");
- *no_add_attrs = true;
- return NULL_TREE;
- }
- return NULL_TREE;
-}
-
-/* Handle a "assume_aligned" attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_assume_aligned_attribute (tree *, tree, tree args, int,
- bool *no_add_attrs)
-{
- for (; args; args = TREE_CHAIN (args))
- {
- tree position = TREE_VALUE (args);
- if (position && TREE_CODE (position) != IDENTIFIER_NODE
- && TREE_CODE (position) != FUNCTION_DECL)
- position = default_conversion (position);
-
- if (TREE_CODE (position) != INTEGER_CST)
- {
- warning (OPT_Wattributes,
- "assume_aligned parameter not integer constant");
- *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 "bnd_variable_size" attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_bnd_variable_size_attribute (tree *node, tree name, tree ARG_UNUSED (args),
- int ARG_UNUSED (flags), bool *no_add_attrs)
-{
- if (TREE_CODE (*node) != FIELD_DECL)
- {
- warning (OPT_Wattributes, "%qE attribute ignored", name);
- *no_add_attrs = true;
- }
-
- return NULL_TREE;
-}
-
-/* Handle a "bnd_legacy" attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_bnd_legacy (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 "bnd_instrument" attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_bnd_instrument (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 "warn_unused" attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_warn_unused_attribute (tree *node, tree name,
- tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
-{
- if (TYPE_P (*node))
- /* Do nothing else, just set the attribute. We'll get at
- it later with lookup_attribute. */
- ;
- else
- {
- warning (OPT_Wattributes, "%qE attribute ignored", name);
- *no_add_attrs = true;
- }
-
- return NULL_TREE;
-}
-
-/* Handle an "omp declare simd" attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_omp_declare_simd_attribute (tree *, tree, tree, int, bool *)
-{
- return NULL_TREE;
-}
-
-/* Handle a "simd" attribute. */
-
-static tree
-handle_simd_attribute (tree *node, tree name, tree args, int, bool *no_add_attrs)
-{
- if (TREE_CODE (*node) == FUNCTION_DECL)
- {
- if (lookup_attribute ("cilk simd function",
- DECL_ATTRIBUTES (*node)) != NULL)
- {
- error_at (DECL_SOURCE_LOCATION (*node),
- "%<__simd__%> attribute cannot be used in the same "
- "function marked as a Cilk Plus SIMD-enabled function");
- *no_add_attrs = true;
- }
- else
- {
- tree t = get_identifier ("omp declare simd");
- tree attr = NULL_TREE;
- if (args)
- {
- tree 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;
- }
-
- if (strcmp (TREE_STRING_POINTER (id), "notinbranch") == 0)
- attr = build_omp_clause (DECL_SOURCE_LOCATION (*node),
- OMP_CLAUSE_NOTINBRANCH);
- else
- if (strcmp (TREE_STRING_POINTER (id), "inbranch") == 0)
- attr = build_omp_clause (DECL_SOURCE_LOCATION (*node),
- OMP_CLAUSE_INBRANCH);
- else
- {
- error ("only %<inbranch%> and %<notinbranch%> flags are "
- "allowed for %<__simd__%> attribute");
- *no_add_attrs = true;
- return NULL_TREE;
- }
- }
-
- DECL_ATTRIBUTES (*node) = tree_cons (t,
- build_tree_list (NULL_TREE,
- attr),
- DECL_ATTRIBUTES (*node));
- }
- }
- else
- {
- warning (OPT_Wattributes, "%qE attribute ignored", name);
- *no_add_attrs = true;
- }
-
- return NULL_TREE;
-}
-
-/* Handle an "omp declare target" attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_omp_declare_target_attribute (tree *, tree, tree, int, bool *)
-{
- 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;
-}
-
-/* Digest an attribute list destined for a transactional memory statement.
- ALLOWED is the set of attributes that are allowed for this statement;
- return the attribute we parsed. Multiple attributes are never allowed. */
-
-int
-parse_tm_stmt_attr (tree attrs, int allowed)
-{
- tree a_seen = NULL;
- int m_seen = 0;
-
- for ( ; attrs ; attrs = TREE_CHAIN (attrs))
- {
- tree a = TREE_PURPOSE (attrs);
- int m = 0;
-
- if (is_attribute_p ("outer", a))
- m = TM_STMT_ATTR_OUTER;
-
- if ((m & allowed) == 0)
- {
- warning (OPT_Wattributes, "%qE attribute directive ignored", a);
- continue;
- }
-
- if (m_seen == 0)
- {
- a_seen = a;
- m_seen = m;
- }
- else if (m_seen == m)
- warning (OPT_Wattributes, "%qE attribute duplicated", a);
- else
- warning (OPT_Wattributes, "%qE attribute follows %qE", a, a_seen);
- }
-
- return m_seen;
-}
-
-/* Transform a TM attribute name into a maskable integer and back.
- Note that NULL (i.e. no attribute) is mapped to UNKNOWN, corresponding
- to how the lack of an attribute is treated. */
-
-int
-tm_attr_to_mask (tree attr)
-{
- if (attr == NULL)
- return 0;
- if (is_attribute_p ("transaction_safe", attr))
- return TM_ATTR_SAFE;
- if (is_attribute_p ("transaction_callable", attr))
- return TM_ATTR_CALLABLE;
- if (is_attribute_p ("transaction_pure", attr))
- return TM_ATTR_PURE;
- if (is_attribute_p ("transaction_unsafe", attr))
- return TM_ATTR_IRREVOCABLE;
- if (is_attribute_p ("transaction_may_cancel_outer", attr))
- return TM_ATTR_MAY_CANCEL_OUTER;
- return 0;
-}
-
-tree
-tm_mask_to_attr (int mask)
-{
- const char *str;
- switch (mask)
- {
- case TM_ATTR_SAFE:
- str = "transaction_safe";
- break;
- case TM_ATTR_CALLABLE:
- str = "transaction_callable";
- break;
- case TM_ATTR_PURE:
- str = "transaction_pure";
- break;
- case TM_ATTR_IRREVOCABLE:
- str = "transaction_unsafe";
- break;
- case TM_ATTR_MAY_CANCEL_OUTER:
- str = "transaction_may_cancel_outer";
- break;
- default:
- gcc_unreachable ();
- }
- return get_identifier (str);
-}
-
-/* Return the first TM attribute seen in LIST. */
-
-tree
-find_tm_attribute (tree list)
-{
- for (; list ; list = TREE_CHAIN (list))
- {
- tree name = TREE_PURPOSE (list);
- if (tm_attr_to_mask (name) != 0)
- return name;
- }
- return NULL_TREE;
-}
-
-/* Handle the TM attributes; arguments as in struct attribute_spec.handler.
- Here we accept only function types, and verify that none of the other
- function TM attributes are also applied. */
-/* ??? We need to accept class types for C++, but not C. This greatly
- complicates this function, since we can no longer rely on the extra
- processing given by function_type_required. */
-
-static tree
-handle_tm_attribute (tree *node, tree name, tree args,
- int flags, bool *no_add_attrs)
-{
- /* Only one path adds the attribute; others don't. */
- *no_add_attrs = true;
-
- switch (TREE_CODE (*node))
- {
- case RECORD_TYPE:
- case UNION_TYPE:
- /* Only tm_callable and tm_safe apply to classes. */
- if (tm_attr_to_mask (name) & ~(TM_ATTR_SAFE | TM_ATTR_CALLABLE))
- goto ignored;
- /* FALLTHRU */
-
- case FUNCTION_TYPE:
- case METHOD_TYPE:
- {
- tree old_name = find_tm_attribute (TYPE_ATTRIBUTES (*node));
- if (old_name == name)
- ;
- else if (old_name != NULL_TREE)
- error ("type was previously declared %qE", old_name);
- else
- *no_add_attrs = false;
- }
- break;
-
- case FUNCTION_DECL:
- {
- /* transaction_safe_dynamic goes on the FUNCTION_DECL, but we also
- want to set transaction_safe on the type. */
- gcc_assert (is_attribute_p ("transaction_safe_dynamic", name));
- if (!TYPE_P (DECL_CONTEXT (*node)))
- error_at (DECL_SOURCE_LOCATION (*node),
- "%<transaction_safe_dynamic%> may only be specified for "
- "a virtual function");
- *no_add_attrs = false;
- decl_attributes (&TREE_TYPE (*node),
- build_tree_list (get_identifier ("transaction_safe"),
- NULL_TREE),
- 0);
- break;
- }
-
- case POINTER_TYPE:
- {
- enum tree_code subcode = TREE_CODE (TREE_TYPE (*node));
- if (subcode == FUNCTION_TYPE || subcode == METHOD_TYPE)
- {
- tree fn_tmp = TREE_TYPE (*node);
- decl_attributes (&fn_tmp, tree_cons (name, args, NULL), 0);
- *node = build_pointer_type (fn_tmp);
- break;
- }
- }
- /* FALLTHRU */
-
- default:
- /* If a function is next, pass it on to be tried next. */
- if (flags & (int) ATTR_FLAG_FUNCTION_NEXT)
- return tree_cons (name, args, NULL);
-
- ignored:
- warning (OPT_Wattributes, "%qE attribute ignored", name);
- break;
- }
-
- return NULL_TREE;
-}
-
-/* Handle the TM_WRAP attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_tm_wrap_attribute (tree *node, tree name, tree args,
- int ARG_UNUSED (flags), bool *no_add_attrs)
-{
- tree decl = *node;
-
- /* We don't need the attribute even on success, since we
- record the entry in an external table. */
- *no_add_attrs = true;
-
- if (TREE_CODE (decl) != FUNCTION_DECL)
- warning (OPT_Wattributes, "%qE attribute ignored", name);
- else
- {
- tree wrap_decl = TREE_VALUE (args);
- if (error_operand_p (wrap_decl))
- ;
- else if (TREE_CODE (wrap_decl) != IDENTIFIER_NODE
- && !VAR_OR_FUNCTION_DECL_P (wrap_decl))
- error ("%qE argument not an identifier", name);
- else
- {
- if (TREE_CODE (wrap_decl) == IDENTIFIER_NODE)
- wrap_decl = lookup_name (wrap_decl);
- if (wrap_decl && TREE_CODE (wrap_decl) == FUNCTION_DECL)
- {
- if (lang_hooks.types_compatible_p (TREE_TYPE (decl),
- TREE_TYPE (wrap_decl)))
- record_tm_replacement (wrap_decl, decl);
- else
- error ("%qD is not compatible with %qD", wrap_decl, decl);
- }
- else
- error ("%qE argument is not a function", name);
- }
- }
-
- return NULL_TREE;
-}
-
-/* Ignore the given attribute. Used when this attribute may be usefully
- overridden by the target, but is not used generically. */
+/* Data to communicate through check_function_arguments_recurse between
+ check_function_nonnull and check_nonnull_arg. */
-static tree
-ignore_attribute (tree * ARG_UNUSED (node), tree ARG_UNUSED (name),
- tree ARG_UNUSED (args), int ARG_UNUSED (flags),
- bool *no_add_attrs)
-{
- *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)
+struct nonnull_arg_ctx
{
- 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
- || VAR_OR_FUNCTION_DECL_P (decl)
- || TREE_CODE (decl) == FIELD_DECL
- || TREE_CODE (decl) == CONST_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;
- machine_mode orig_mode;
- tree type = *node, new_type, size;
-
- *no_add_attrs = true;
-
- size = TREE_VALUE (args);
- if (size && TREE_CODE (size) != IDENTIFIER_NODE
- && TREE_CODE (size) != FUNCTION_DECL)
- size = default_conversion (size);
-
- if (!tree_fits_uhwi_p (size))
- {
- warning (OPT_Wattributes, "%qE attribute ignored", name);
- return NULL_TREE;
- }
-
- /* Get the vector size (in bytes). */
- vecsize = tree_to_uhwi (size);
-
- /* 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))
- || !tree_fits_uhwi_p (TYPE_SIZE_UNIT (type))
- || TREE_CODE (type) == BOOLEAN_TYPE)
- {
- error ("invalid vector type for attribute %qE", name);
- return NULL_TREE;
- }
-
- if (vecsize % tree_to_uhwi (TYPE_SIZE_UNIT (type)))
- {
- 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_to_uhwi (TYPE_SIZE_UNIT (type));
- 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; attr_arg_num++, args = TREE_CHAIN (args))
- {
- unsigned HOST_WIDE_INT arg_num = 0, ck_num;
-
- tree arg = TREE_VALUE (args);
- if (arg && TREE_CODE (arg) != IDENTIFIER_NODE
- && TREE_CODE (arg) != FUNCTION_DECL)
- arg = default_conversion (arg);
-
- if (!get_nonnull_operand (arg, &arg_num))
- {
- error ("nonnull argument has invalid operand number (argument %lu)",
- (unsigned long) attr_arg_num);
- *no_add_attrs = true;
- return NULL_TREE;
- }
-
- if (prototype_p (type))
- {
- function_args_iterator iter;
- tree argument;
-
- function_args_iter_init (&iter, type);
- for (ck_num = 1; ; ck_num++, function_args_iter_next (&iter))
- {
- argument = function_args_iter_cond (&iter);
- if (argument == NULL_TREE || ck_num == arg_num)
- break;
- }
-
- if (!argument
- || TREE_CODE (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 (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;
-}
+ location_t loc;
+ bool warned_p;
+};
/* 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. */
+ arguments are passed in the array ARGARRAY. Return true if we have
+ warned. */
-static void
+static bool
check_function_nonnull (location_t loc, tree attrs, int nargs, tree *argarray)
{
tree a;
@@ -9118,7 +5263,7 @@ check_function_nonnull (location_t loc, tree attrs, int nargs, tree *argarray)
attrs = lookup_attribute ("nonnull", attrs);
if (attrs == NULL_TREE)
- return;
+ return false;
a = attrs;
/* See if any of the nonnull attributes has no arguments. If so,
@@ -9129,9 +5274,10 @@ check_function_nonnull (location_t loc, tree attrs, int nargs, tree *argarray)
a = lookup_attribute ("nonnull", TREE_CHAIN (a));
while (a != NULL_TREE && TREE_VALUE (a) != NULL_TREE);
+ struct nonnull_arg_ctx ctx = { loc, false };
if (a != NULL_TREE)
for (i = 0; i < nargs; i++)
- check_function_arguments_recurse (check_nonnull_arg, &loc, argarray[i],
+ check_function_arguments_recurse (check_nonnull_arg, &ctx, argarray[i],
i + 1);
else
{
@@ -9147,10 +5293,11 @@ check_function_nonnull (location_t loc, tree attrs, int nargs, tree *argarray)
}
if (a != NULL_TREE)
- check_function_arguments_recurse (check_nonnull_arg, &loc,
+ check_function_arguments_recurse (check_nonnull_arg, &ctx,
argarray[i], i + 1);
}
}
+ return ctx.warned_p;
}
/* Check that the Nth argument of a function call (counting backwards
@@ -9207,6 +5354,49 @@ check_function_sentinel (const_tree fntype, int nargs, tree *argarray)
}
}
+/* Check that the same argument isn't passed to restrict arguments
+ and other arguments. */
+
+static void
+check_function_restrict (const_tree fndecl, const_tree fntype,
+ int nargs, tree *argarray)
+{
+ int i;
+ tree parms;
+
+ if (fndecl
+ && TREE_CODE (fndecl) == FUNCTION_DECL
+ && DECL_ARGUMENTS (fndecl))
+ parms = DECL_ARGUMENTS (fndecl);
+ else
+ parms = TYPE_ARG_TYPES (fntype);
+
+ for (i = 0; i < nargs; i++)
+ TREE_VISITED (argarray[i]) = 0;
+
+ for (i = 0; i < nargs && parms && parms != void_list_node; i++)
+ {
+ tree type;
+ if (TREE_CODE (parms) == PARM_DECL)
+ {
+ type = TREE_TYPE (parms);
+ parms = DECL_CHAIN (parms);
+ }
+ else
+ {
+ type = TREE_VALUE (parms);
+ parms = TREE_CHAIN (parms);
+ }
+ if (POINTER_TYPE_P (type)
+ && TYPE_RESTRICT (type)
+ && !TYPE_READONLY (TREE_TYPE (type)))
+ warn_for_restrict (i, argarray, nargs);
+ }
+
+ for (i = 0; i < nargs; i++)
+ TREE_VISITED (argarray[i]) = 0;
+}
+
/* 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. */
@@ -9235,7 +5425,7 @@ nonnull_check_p (tree args, unsigned HOST_WIDE_INT param_num)
static void
check_nonnull_arg (void *ctx, tree param, unsigned HOST_WIDE_INT param_num)
{
- location_t *ploc = (location_t *) ctx;
+ struct nonnull_arg_ctx *pctx = (struct nonnull_arg_ctx *) ctx;
/* Just skip checking the argument if it's not a pointer. This can
happen if the "nonnull" attribute was given without an operand
@@ -9244,15 +5434,21 @@ check_nonnull_arg (void *ctx, tree param, unsigned HOST_WIDE_INT param_num)
if (TREE_CODE (TREE_TYPE (param)) != POINTER_TYPE)
return;
+ /* When not optimizing diagnose the simple cases of null arguments.
+ When optimization is enabled defer the checking until expansion
+ when more cases can be detected. */
if (integer_zerop (param))
- warning_at (*ploc, OPT_Wnonnull, "null argument where non-null required "
- "(argument %lu)", (unsigned long) param_num);
+ {
+ warning_at (pctx->loc, OPT_Wnonnull, "null argument where non-null "
+ "required (argument %lu)", (unsigned long) param_num);
+ pctx->warned_p = true;
+ }
}
/* Helper for nonnull attribute handling; fetch the operand number
from the attribute argument list. */
-static bool
+bool
get_nonnull_operand (tree arg_num_expr, unsigned HOST_WIDE_INT *valp)
{
/* Verify the arg number is a small constant. */
@@ -9265,211 +5461,6 @@ get_nonnull_operand (tree arg_num_expr, unsigned HOST_WIDE_INT *valp)
return false;
}
-/* 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 (!VAR_P (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)
-{
- if (!prototype_p (*node))
- {
- warning (OPT_Wattributes,
- "%qE attribute requires prototypes with named arguments", name);
- *no_add_attrs = true;
- }
- else
- {
- if (!stdarg_p (*node))
- {
- warning (OPT_Wattributes,
- "%qE attribute only applies to variadic functions", name);
- *no_add_attrs = true;
- }
- }
-
- if (args)
- {
- tree position = TREE_VALUE (args);
- if (position && TREE_CODE (position) != IDENTIFIER_NODE
- && TREE_CODE (position) != FUNCTION_DECL)
- position = default_conversion (position);
-
- if (TREE_CODE (position) != INTEGER_CST
- || !INTEGRAL_TYPE_P (TREE_TYPE (position)))
- {
- 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))
-{
- /* Ensure we have a function type. */
- gcc_assert (TREE_CODE (*node) == FUNCTION_TYPE);
-
- /* Ensure we have a variadic function. */
- gcc_assert (!prototype_p (*node) || stdarg_p (*node));
-
- 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 (lookup_attribute ("target_clones", DECL_ATTRIBUTES (*node)))
- {
- warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
- "with %qs attribute", name, "target_clones");
- *no_add_attrs = true;
- }
- else if (! targetm.target_option.valid_attribute_p (*node, name, args,
- flags))
- *no_add_attrs = true;
-
- return NULL_TREE;
-}
-
-/* Handle a "target_clones" attribute. */
-
-static tree
-handle_target_clones_attribute (tree *node, tree name, tree ARG_UNUSED (args),
- int ARG_UNUSED (flags), bool *no_add_attrs)
-{
- /* Ensure we have a function type. */
- if (TREE_CODE (*node) == FUNCTION_DECL)
- {
- if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (*node)))
- {
- warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
- "with %qs attribute", name, "always_inline");
- *no_add_attrs = true;
- }
- else if (lookup_attribute ("target", DECL_ATTRIBUTES (*node)))
- {
- warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
- "with %qs attribute", name, "target");
- *no_add_attrs = true;
- }
- else
- /* Do not inline functions with multiple clone targets. */
- DECL_UNINLINABLE (*node) = 1;
- }
- else
- {
- warning (OPT_Wattributes, "%qE attribute ignored", name);
- *no_add_attrs = true;
- }
- return NULL_TREE;
-}
-
/* Arguments being collected for optimization. */
typedef const char *const_char_p; /* For DEF_VEC_P. */
static GTY(()) vec<const_char_p, va_gc> *optimize_args;
@@ -9543,10 +5534,10 @@ parse_optimize_options (tree args, bool attr_p)
ret = false;
if (attr_p)
warning (OPT_Wattributes,
- "bad option %s to optimize attribute", p);
+ "bad option %qs to attribute %<optimize%>", p);
else
warning (OPT_Wpragmas,
- "bad option %s to pragma attribute", p);
+ "bad option %qs to pragma %<optimize%>", p);
continue;
}
@@ -9581,6 +5572,29 @@ parse_optimize_options (tree args, bool attr_p)
decode_cmdline_options_to_array_default_mask (opt_argc, opt_argv,
&decoded_options,
&decoded_options_count);
+ /* Drop non-Optimization options. */
+ unsigned j = 1;
+ for (i = 1; i < decoded_options_count; ++i)
+ {
+ if (! (cl_options[decoded_options[i].opt_index].flags & CL_OPTIMIZATION))
+ {
+ ret = false;
+ if (attr_p)
+ warning (OPT_Wattributes,
+ "bad option %qs to attribute %<optimize%>",
+ decoded_options[i].orig_option_with_args_text);
+ else
+ warning (OPT_Wpragmas,
+ "bad option %qs to pragma %<optimize%>",
+ decoded_options[i].orig_option_with_args_text);
+ continue;
+ }
+ if (i != j)
+ decoded_options[j] = decoded_options[i];
+ j++;
+ }
+ decoded_options_count = j;
+ /* And apply them. */
decode_options (&global_options, &global_options_set,
decoded_options, decoded_options_count,
input_location, global_dc);
@@ -9591,115 +5605,50 @@ parse_optimize_options (tree args, bool attr_p)
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 (&global_options);
-
- /* 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;
-}
-
-/* Handle a "returns_nonnull" attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_returns_nonnull_attribute (tree *node, tree, tree, int,
- bool *no_add_attrs)
-{
- // Even without a prototype we still have a return type we can check.
- if (TREE_CODE (TREE_TYPE (*node)) != POINTER_TYPE)
- {
- error ("returns_nonnull attribute on a function not returning a pointer");
- *no_add_attrs = true;
- }
- return NULL_TREE;
-}
-
-/* Handle a "designated_init" attribute; arguments as in
- struct attribute_spec.handler. */
+/* Check whether ATTR is a valid attribute fallthrough. */
-static tree
-handle_designated_init_attribute (tree *node, tree name, tree, int,
- bool *no_add_attrs)
+bool
+attribute_fallthrough_p (tree attr)
{
- if (TREE_CODE (*node) != RECORD_TYPE)
- {
- error ("%qE attribute is only valid on %<struct%> type", name);
- *no_add_attrs = true;
+ if (attr == error_mark_node)
+ return false;
+ tree t = lookup_attribute ("fallthrough", attr);
+ if (t == NULL_TREE)
+ return false;
+ /* This attribute shall appear at most once in each attribute-list. */
+ if (lookup_attribute ("fallthrough", TREE_CHAIN (t)))
+ warning (OPT_Wattributes, "%<fallthrough%> attribute specified multiple "
+ "times");
+ /* No attribute-argument-clause shall be present. */
+ else if (TREE_VALUE (t) != NULL_TREE)
+ warning (OPT_Wattributes, "%<fallthrough%> attribute specified with "
+ "a parameter");
+ /* Warn if other attributes are found. */
+ for (t = attr; t != NULL_TREE; t = TREE_CHAIN (t))
+ {
+ tree name = get_attribute_name (t);
+ if (!is_attribute_p ("fallthrough", name))
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
}
- return NULL_TREE;
+ return true;
}
/* Check for valid arguments being passed to a function with FNTYPE.
There are NARGS arguments in the array ARGARRAY. LOC should be used for
- diagnostics. */
-void
-check_function_arguments (location_t loc, const_tree fntype, int nargs,
- tree *argarray)
+ diagnostics. Return true if -Wnonnull warning has been diagnosed. */
+bool
+check_function_arguments (location_t loc, const_tree fndecl, const_tree fntype,
+ int nargs, tree *argarray)
{
+ bool warned_p = false;
+
/* 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 (loc, TYPE_ATTRIBUTES (fntype), nargs, argarray);
+ warned_p = check_function_nonnull (loc, TYPE_ATTRIBUTES (fntype),
+ nargs, argarray);
/* Check for errors in format strings. */
@@ -9708,6 +5657,10 @@ check_function_arguments (location_t loc, const_tree fntype, int nargs,
if (warn_format)
check_function_sentinel (fntype, nargs, argarray);
+
+ if (warn_restrict)
+ check_function_restrict (fndecl, fntype, nargs, argarray);
+ return warned_p;
}
/* Generic argument checking recursion routine. PARAM is the argument to
@@ -9798,31 +5751,39 @@ check_function_arguments_recurse (void (*callback)
/* 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. */
+ correct, otherwise false. LOC is the location of FNDECL. */
static bool
-builtin_function_validate_nargs (tree fndecl, int nargs, int required)
+builtin_function_validate_nargs (location_t loc, tree fndecl, int nargs,
+ int required)
{
if (nargs < required)
{
- error_at (input_location,
- "not enough arguments to function %qE", fndecl);
+ error_at (loc, "too few arguments to function %qE", fndecl);
return false;
}
else if (nargs > required)
{
- error_at (input_location,
- "too many arguments to function %qE", fndecl);
+ error_at (loc, "too many arguments to function %qE", fndecl);
return false;
}
return true;
}
+/* Helper macro for check_builtin_function_arguments. */
+#define ARG_LOCATION(N) \
+ (arg_loc.is_empty () \
+ ? EXPR_LOC_OR_LOC (args[(N)], input_location) \
+ : expansion_point_location (arg_loc[(N)]))
+
/* Verifies the NARGS arguments ARGS to the builtin function FNDECL.
- Returns false if there was an error, otherwise true. */
+ Returns false if there was an error, otherwise true. LOC is the
+ location of the function; ARG_LOC is a vector of locations of the
+ arguments. */
bool
-check_builtin_function_arguments (tree fndecl, int nargs, tree *args)
+check_builtin_function_arguments (location_t loc, vec<location_t> arg_loc,
+ tree fndecl, int nargs, tree *args)
{
if (!DECL_BUILT_IN (fndecl)
|| DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL)
@@ -9844,21 +5805,21 @@ check_builtin_function_arguments (tree fndecl, int nargs, tree *args)
/* The maximum alignment in bits corresponding to the same
maximum in bytes enforced in check_user_alignment(). */
unsigned maxalign = (UINT_MAX >> 1) + 1;
-
+
/* Reject invalid alignments. */
if (align < BITS_PER_UNIT || maxalign < align)
{
- error_at (EXPR_LOC_OR_LOC (args[1], input_location),
+ error_at (ARG_LOCATION (1),
"second argument to function %qE must be a constant "
"integer power of 2 between %qi and %qu bits",
fndecl, BITS_PER_UNIT, maxalign);
return false;
}
- return true;
+ return true;
}
case BUILT_IN_CONSTANT_P:
- return builtin_function_validate_nargs (fndecl, nargs, 1);
+ return builtin_function_validate_nargs (loc, fndecl, nargs, 1);
case BUILT_IN_ISFINITE:
case BUILT_IN_ISINF:
@@ -9866,12 +5827,12 @@ check_builtin_function_arguments (tree fndecl, int nargs, tree *args)
case BUILT_IN_ISNAN:
case BUILT_IN_ISNORMAL:
case BUILT_IN_SIGNBIT:
- if (builtin_function_validate_nargs (fndecl, nargs, 1))
+ if (builtin_function_validate_nargs (loc, fndecl, nargs, 1))
{
if (TREE_CODE (TREE_TYPE (args[0])) != REAL_TYPE)
{
- error ("non-floating-point argument in call to "
- "function %qE", fndecl);
+ error_at (ARG_LOCATION (0), "non-floating-point argument in "
+ "call to function %qE", fndecl);
return false;
}
return true;
@@ -9884,7 +5845,7 @@ check_builtin_function_arguments (tree fndecl, int nargs, tree *args)
case BUILT_IN_ISLESSEQUAL:
case BUILT_IN_ISLESSGREATER:
case BUILT_IN_ISUNORDERED:
- if (builtin_function_validate_nargs (fndecl, nargs, 2))
+ if (builtin_function_validate_nargs (loc, fndecl, nargs, 2))
{
enum tree_code code0, code1;
code0 = TREE_CODE (TREE_TYPE (args[0]));
@@ -9893,8 +5854,8 @@ check_builtin_function_arguments (tree fndecl, int nargs, tree *args)
|| (code0 == REAL_TYPE && code1 == INTEGER_TYPE)
|| (code0 == INTEGER_TYPE && code1 == REAL_TYPE)))
{
- error ("non-floating-point arguments in call to "
- "function %qE", fndecl);
+ error_at (loc, "non-floating-point arguments in call to "
+ "function %qE", fndecl);
return false;
}
return true;
@@ -9902,22 +5863,20 @@ check_builtin_function_arguments (tree fndecl, int nargs, tree *args)
return false;
case BUILT_IN_FPCLASSIFY:
- if (builtin_function_validate_nargs (fndecl, nargs, 6))
+ if (builtin_function_validate_nargs (loc, fndecl, nargs, 6))
{
- unsigned i;
-
- for (i=0; i<5; i++)
+ for (unsigned int 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);
+ error_at (ARG_LOCATION (i), "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);
+ error_at (ARG_LOCATION (5), "non-floating-point argument in "
+ "call to function %qE", fndecl);
return false;
}
return true;
@@ -9925,11 +5884,12 @@ check_builtin_function_arguments (tree fndecl, int nargs, tree *args)
return false;
case BUILT_IN_ASSUME_ALIGNED:
- if (builtin_function_validate_nargs (fndecl, nargs, 2 + (nargs > 2)))
+ if (builtin_function_validate_nargs (loc, fndecl, nargs, 2 + (nargs > 2)))
{
if (nargs >= 3 && TREE_CODE (TREE_TYPE (args[2])) != INTEGER_TYPE)
{
- error ("non-integer argument 3 in call to function %qE", fndecl);
+ error_at (ARG_LOCATION (2), "non-integer argument 3 in call to "
+ "function %qE", fndecl);
return false;
}
return true;
@@ -9939,21 +5899,62 @@ check_builtin_function_arguments (tree fndecl, int nargs, tree *args)
case BUILT_IN_ADD_OVERFLOW:
case BUILT_IN_SUB_OVERFLOW:
case BUILT_IN_MUL_OVERFLOW:
- if (builtin_function_validate_nargs (fndecl, nargs, 3))
+ if (builtin_function_validate_nargs (loc, fndecl, nargs, 3))
{
unsigned i;
for (i = 0; i < 2; i++)
if (!INTEGRAL_TYPE_P (TREE_TYPE (args[i])))
{
- error ("argument %u in call to function %qE does not have "
- "integral type", i + 1, fndecl);
+ error_at (ARG_LOCATION (i), "argument %u in call to function "
+ "%qE does not have integral type", i + 1, fndecl);
return false;
}
if (TREE_CODE (TREE_TYPE (args[2])) != POINTER_TYPE
- || TREE_CODE (TREE_TYPE (TREE_TYPE (args[2]))) != INTEGER_TYPE)
+ || !INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (args[2]))))
+ {
+ error_at (ARG_LOCATION (2), "argument 3 in call to function %qE "
+ "does not have pointer to integral type", fndecl);
+ return false;
+ }
+ else if (TREE_CODE (TREE_TYPE (TREE_TYPE (args[2]))) == ENUMERAL_TYPE)
+ {
+ error_at (ARG_LOCATION (2), "argument 3 in call to function %qE "
+ "has pointer to enumerated type", fndecl);
+ return false;
+ }
+ else if (TREE_CODE (TREE_TYPE (TREE_TYPE (args[2]))) == BOOLEAN_TYPE)
+ {
+ error_at (ARG_LOCATION (2), "argument 3 in call to function %qE "
+ "has pointer to boolean type", fndecl);
+ return false;
+ }
+ return true;
+ }
+ return false;
+
+ case BUILT_IN_ADD_OVERFLOW_P:
+ case BUILT_IN_SUB_OVERFLOW_P:
+ case BUILT_IN_MUL_OVERFLOW_P:
+ if (builtin_function_validate_nargs (loc, fndecl, nargs, 3))
+ {
+ unsigned i;
+ for (i = 0; i < 3; i++)
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (args[i])))
+ {
+ error_at (ARG_LOCATION (i), "argument %u in call to function "
+ "%qE does not have integral type", i + 1, fndecl);
+ return false;
+ }
+ if (TREE_CODE (TREE_TYPE (args[2])) == ENUMERAL_TYPE)
{
- error ("argument 3 in call to function %qE does not have "
- "pointer to integer type", fndecl);
+ error_at (ARG_LOCATION (2), "argument 3 in call to function "
+ "%qE has enumerated type", fndecl);
+ return false;
+ }
+ else if (TREE_CODE (TREE_TYPE (args[2])) == BOOLEAN_TYPE)
+ {
+ error_at (ARG_LOCATION (2), "argument 3 in call to function "
+ "%qE has boolean type", fndecl);
return false;
}
return true;
@@ -10374,160 +6375,6 @@ 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 (location_t loc, 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_at (loc, 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_at (loc, 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 (VAR_P (arg))
- error_at (loc, 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_at (loc, 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_at (loc, 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_at (loc, 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_at (loc, 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_ARROW_STAR:
- 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
@@ -10539,7 +6386,6 @@ 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;
bool overflow_p = false;
maxindex = size_zero_node;
@@ -10633,13 +6479,16 @@ complete_array_type (tree *ptype, tree initial_value, bool do_default)
TYPE_DOMAIN (main_type)
= build_range_type (TREE_TYPE (maxindex),
build_int_cst (TREE_TYPE (maxindex), 0), maxindex);
+ TYPE_TYPELESS_STORAGE (main_type) = TYPE_TYPELESS_STORAGE (type);
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);
+ inchash::hash hstate;
+ hstate.add_object (TYPE_HASH (unqual_elt));
+ hstate.add_object (TYPE_HASH (TYPE_DOMAIN (main_type)));
+ if (!AGGREGATE_TYPE_P (unqual_elt))
+ hstate.add_flag (TYPE_TYPELESS_STORAGE (main_type));
+ main_type = type_hash_canon (hstate.end (), main_type);
/* Fix the canonical type. */
if (TYPE_STRUCTURAL_EQUALITY_P (TREE_TYPE (main_type))
@@ -10650,7 +6499,8 @@ complete_array_type (tree *ptype, tree initial_value, bool do_default)
!= TYPE_DOMAIN (main_type)))
TYPE_CANONICAL (main_type)
= build_array_type (TYPE_CANONICAL (TREE_TYPE (main_type)),
- TYPE_CANONICAL (TYPE_DOMAIN (main_type)));
+ TYPE_CANONICAL (TYPE_DOMAIN (main_type)),
+ TYPE_TYPELESS_STORAGE (main_type));
else
TYPE_CANONICAL (main_type) = main_type;
@@ -10677,11 +6527,16 @@ complete_array_type (tree *ptype, tree initial_value, bool do_default)
void
c_common_mark_addressable_vec (tree t)
{
+ if (TREE_CODE (t) == C_MAYBE_CONST_EXPR)
+ t = C_MAYBE_CONST_EXPR_EXPR (t);
while (handled_component_p (t))
t = TREE_OPERAND (t, 0);
- if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL)
+ if (!VAR_P (t)
+ && TREE_CODE (t) != PARM_DECL
+ && TREE_CODE (t) != COMPOUND_LITERAL_EXPR)
return;
- TREE_ADDRESSABLE (t) = 1;
+ if (!VAR_P (t) || !DECL_HARD_REGISTER (t))
+ TREE_ADDRESSABLE (t) = 1;
}
@@ -10934,6 +6789,20 @@ get_atomic_generic_size (location_t loc, tree function,
function);
return 0;
}
+ else if (TYPE_SIZE_UNIT (TREE_TYPE (type))
+ && TREE_CODE ((TYPE_SIZE_UNIT (TREE_TYPE (type))))
+ != INTEGER_CST)
+ {
+ error_at (loc, "argument %d of %qE must be a pointer to a constant "
+ "size type", x + 1, function);
+ return 0;
+ }
+ else if (FUNCTION_POINTER_TYPE_P (type))
+ {
+ error_at (loc, "argument %d of %qE must not be a pointer to a "
+ "function", x + 1, function);
+ return 0;
+ }
tree type_size = TYPE_SIZE_UNIT (TREE_TYPE (type));
size = type_size ? tree_to_uhwi (type_size) : 0;
if (size != size_0)
@@ -11338,7 +7207,7 @@ resolve_overloaded_builtin (location_t loc, tree function,
/* Handle these 4 together so that they can fall through to the next
case if the call is transformed to an _N variant. */
switch (orig_code)
- {
+ {
case BUILT_IN_ATOMIC_EXCHANGE:
{
if (resolve_overloaded_atomic_exchange (loc, function, params,
@@ -11379,17 +7248,15 @@ resolve_overloaded_builtin (location_t loc, tree function,
}
default:
gcc_unreachable ();
- }
- /* Fallthrough to the normal processing. */
+ }
}
+ /* FALLTHRU */
case BUILT_IN_ATOMIC_EXCHANGE_N:
case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_N:
case BUILT_IN_ATOMIC_LOAD_N:
case BUILT_IN_ATOMIC_STORE_N:
- {
- fetch_op = false;
- /* Fallthrough to further processing. */
- }
+ fetch_op = false;
+ /* FALLTHRU */
case BUILT_IN_ATOMIC_ADD_FETCH_N:
case BUILT_IN_ATOMIC_SUB_FETCH_N:
case BUILT_IN_ATOMIC_AND_FETCH_N:
@@ -11402,10 +7269,8 @@ resolve_overloaded_builtin (location_t loc, tree function,
case BUILT_IN_ATOMIC_FETCH_NAND_N:
case BUILT_IN_ATOMIC_FETCH_XOR_N:
case BUILT_IN_ATOMIC_FETCH_OR_N:
- {
- orig_format = false;
- /* Fallthru for parameter processing. */
- }
+ orig_format = false;
+ /* FALLTHRU */
case BUILT_IN_SYNC_FETCH_AND_ADD_N:
case BUILT_IN_SYNC_FETCH_AND_SUB_N:
case BUILT_IN_SYNC_FETCH_AND_OR_N:
@@ -11452,7 +7317,8 @@ resolve_overloaded_builtin (location_t loc, tree function,
return result;
if (orig_code != BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_N
&& orig_code != BUILT_IN_SYNC_LOCK_RELEASE_N
- && orig_code != BUILT_IN_ATOMIC_STORE_N)
+ && orig_code != BUILT_IN_ATOMIC_STORE_N
+ && orig_code != BUILT_IN_ATOMIC_COMPARE_EXCHANGE_N)
result = sync_resolve_return (first_param, result, orig_format);
if (fetch_op)
@@ -11546,426 +7412,6 @@ check_missing_format_attribute (tree ltype, tree rtype)
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 (location_t loc, tree index)
-{
- if (TYPE_MAIN_VARIANT (TREE_TYPE (index)) == char_type_node
- && TREE_CODE (index) != INTEGER_CST)
- warning_at (loc, 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 (location_t loc, 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)
- warning_at (EXPR_LOC_OR_LOC (arg_left, loc), OPT_Wparentheses,
- "suggest parentheses around %<+%> inside %<<<%>");
- else if (code_right == PLUS_EXPR)
- warning_at (EXPR_LOC_OR_LOC (arg_right, loc), OPT_Wparentheses,
- "suggest parentheses around %<+%> inside %<<<%>");
- else if (code_left == MINUS_EXPR)
- warning_at (EXPR_LOC_OR_LOC (arg_left, loc), OPT_Wparentheses,
- "suggest parentheses around %<-%> inside %<<<%>");
- else if (code_right == MINUS_EXPR)
- warning_at (EXPR_LOC_OR_LOC (arg_right, loc), OPT_Wparentheses,
- "suggest parentheses around %<-%> inside %<<<%>");
- return;
-
- case RSHIFT_EXPR:
- if (code_left == PLUS_EXPR)
- warning_at (EXPR_LOC_OR_LOC (arg_left, loc), OPT_Wparentheses,
- "suggest parentheses around %<+%> inside %<>>%>");
- else if (code_right == PLUS_EXPR)
- warning_at (EXPR_LOC_OR_LOC (arg_right, loc), OPT_Wparentheses,
- "suggest parentheses around %<+%> inside %<>>%>");
- else if (code_left == MINUS_EXPR)
- warning_at (EXPR_LOC_OR_LOC (arg_left, loc), OPT_Wparentheses,
- "suggest parentheses around %<-%> inside %<>>%>");
- else if (code_right == MINUS_EXPR)
- warning_at (EXPR_LOC_OR_LOC (arg_right, loc), OPT_Wparentheses,
- "suggest parentheses around %<-%> inside %<>>%>");
- return;
-
- case TRUTH_ORIF_EXPR:
- if (code_left == TRUTH_ANDIF_EXPR)
- warning_at (EXPR_LOC_OR_LOC (arg_left, loc), OPT_Wparentheses,
- "suggest parentheses around %<&&%> within %<||%>");
- else if (code_right == TRUTH_ANDIF_EXPR)
- warning_at (EXPR_LOC_OR_LOC (arg_right, loc), 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)
- warning_at (EXPR_LOC_OR_LOC (arg_left, loc), OPT_Wparentheses,
- "suggest parentheses around arithmetic in operand of %<|%>");
- else if (code_right == BIT_AND_EXPR || code_right == BIT_XOR_EXPR
- || code_right == PLUS_EXPR || code_right == MINUS_EXPR)
- warning_at (EXPR_LOC_OR_LOC (arg_right, loc), OPT_Wparentheses,
- "suggest parentheses around arithmetic in operand of %<|%>");
- /* Check cases like x|y==z */
- else if (TREE_CODE_CLASS (code_left) == tcc_comparison)
- warning_at (EXPR_LOC_OR_LOC (arg_left, loc), OPT_Wparentheses,
- "suggest parentheses around comparison in operand of %<|%>");
- else if (TREE_CODE_CLASS (code_right) == tcc_comparison)
- warning_at (EXPR_LOC_OR_LOC (arg_right, loc), 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_at (EXPR_LOC_OR_LOC (arg_left, loc), 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)
- warning_at (EXPR_LOC_OR_LOC (arg_left, loc), OPT_Wparentheses,
- "suggest parentheses around arithmetic in operand of %<^%>");
- else if (code_right == BIT_AND_EXPR
- || code_right == PLUS_EXPR || code_right == MINUS_EXPR)
- warning_at (EXPR_LOC_OR_LOC (arg_right, loc), OPT_Wparentheses,
- "suggest parentheses around arithmetic in operand of %<^%>");
- /* Check cases like x^y==z */
- else if (TREE_CODE_CLASS (code_left) == tcc_comparison)
- warning_at (EXPR_LOC_OR_LOC (arg_left, loc), OPT_Wparentheses,
- "suggest parentheses around comparison in operand of %<^%>");
- else if (TREE_CODE_CLASS (code_right) == tcc_comparison)
- warning_at (EXPR_LOC_OR_LOC (arg_right, loc), OPT_Wparentheses,
- "suggest parentheses around comparison in operand of %<^%>");
- return;
-
- case BIT_AND_EXPR:
- if (code_left == PLUS_EXPR)
- warning_at (EXPR_LOC_OR_LOC (arg_left, loc), OPT_Wparentheses,
- "suggest parentheses around %<+%> in operand of %<&%>");
- else if (code_right == PLUS_EXPR)
- warning_at (EXPR_LOC_OR_LOC (arg_right, loc), OPT_Wparentheses,
- "suggest parentheses around %<+%> in operand of %<&%>");
- else if (code_left == MINUS_EXPR)
- warning_at (EXPR_LOC_OR_LOC (arg_left, loc), OPT_Wparentheses,
- "suggest parentheses around %<-%> in operand of %<&%>");
- else if (code_right == MINUS_EXPR)
- warning_at (EXPR_LOC_OR_LOC (arg_right, loc), OPT_Wparentheses,
- "suggest parentheses around %<-%> in operand of %<&%>");
- /* Check cases like x&y==z */
- else if (TREE_CODE_CLASS (code_left) == tcc_comparison)
- warning_at (EXPR_LOC_OR_LOC (arg_left, loc), OPT_Wparentheses,
- "suggest parentheses around comparison in operand of %<&%>");
- else if (TREE_CODE_CLASS (code_right) == tcc_comparison)
- warning_at (EXPR_LOC_OR_LOC (arg_right, loc), 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_at (EXPR_LOC_OR_LOC (arg_left, loc), OPT_Wparentheses,
- "suggest parentheses around operand of "
- "%<!%> or change %<&%> to %<&&%> or %<!%> to %<~%>");
- return;
-
- case EQ_EXPR:
- if (TREE_CODE_CLASS (code_left) == tcc_comparison)
- warning_at (EXPR_LOC_OR_LOC (arg_left, loc), OPT_Wparentheses,
- "suggest parentheses around comparison in operand of %<==%>");
- else if (TREE_CODE_CLASS (code_right) == tcc_comparison)
- warning_at (EXPR_LOC_OR_LOC (arg_right, loc), OPT_Wparentheses,
- "suggest parentheses around comparison in operand of %<==%>");
- return;
- case NE_EXPR:
- if (TREE_CODE_CLASS (code_left) == tcc_comparison)
- warning_at (EXPR_LOC_OR_LOC (arg_left, loc), OPT_Wparentheses,
- "suggest parentheses around comparison in operand of %<!=%>");
- else if (TREE_CODE_CLASS (code_right) == tcc_comparison)
- warning_at (EXPR_LOC_OR_LOC (arg_right, loc), OPT_Wparentheses,
- "suggest parentheses around comparison in operand of %<!=%>");
- return;
-
- default:
- if (TREE_CODE_CLASS (code) == tcc_comparison)
- {
- if (TREE_CODE_CLASS (code_left) == tcc_comparison
- && code_left != NE_EXPR && code_left != EQ_EXPR
- && INTEGRAL_TYPE_P (TREE_TYPE (arg_left)))
- warning_at (EXPR_LOC_OR_LOC (arg_left, loc), OPT_Wparentheses,
- "comparisons like %<X<=Y<=Z%> do not "
- "have their mathematical meaning");
- else if (TREE_CODE_CLASS (code_right) == tcc_comparison
- && code_right != NE_EXPR && code_right != EQ_EXPR
- && INTEGRAL_TYPE_P (TREE_TYPE (arg_right)))
- warning_at (EXPR_LOC_OR_LOC (arg_right, loc), 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);
- }
-}
-
-/* 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 = c_common_get_narrower (op0, &unsignedp0);
- op1 = c_common_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 = c_common_get_narrower (TREE_OPERAND (op0, 0), &unsignedp0);
- if (TREE_CODE (op1) == BIT_NOT_EXPR)
- op1 = c_common_get_narrower (TREE_OPERAND (op1, 0), &unsignedp1);
-
- if (tree_fits_shwi_p (op0) || tree_fits_shwi_p (op1))
- {
- tree primop;
- HOST_WIDE_INT constant, mask;
- int unsignedp;
- unsigned int bits;
-
- if (tree_fits_shwi_p (op0))
- {
- primop = op1;
- unsignedp = unsignedp1;
- constant = tree_to_shwi (op0);
- }
- else
- {
- primop = op0;
- unsignedp = unsignedp0;
- constant = tree_to_shwi (op1);
- }
-
- bits = TYPE_PRECISION (TREE_TYPE (primop));
- if (bits < TYPE_PRECISION (result_type)
- && bits < HOST_BITS_PER_LONG && unsignedp)
- {
- mask = (~ (unsigned HOST_WIDE_INT) 0) << bits;
- if ((mask & constant) != mask)
- {
- if (constant == 0)
- warning_at (location, 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);
-}
-
-/* Possibly warn about unused parameters. */
-
-void
-do_warn_unused_parameter (tree fn)
-{
- tree decl;
-
- for (decl = DECL_ARGUMENTS (fn);
- decl; decl = DECL_CHAIN (decl))
- if (!TREE_USED (decl) && TREE_CODE (decl) == PARM_DECL
- && DECL_NAME (decl) && !DECL_ARTIFICIAL (decl)
- && !TREE_NO_WARNING (decl))
- warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wunused_parameter,
- "unused parameter %qD", decl);
-}
-
-
/* Setup a TYPE_DECL node as a typedef representation.
X is a TYPE_DECL for a typedef statement. Create a brand new
@@ -12011,7 +7457,7 @@ set_underlying_type (tree x)
{
if (x == error_mark_node)
return;
- if (DECL_IS_BUILTIN (x))
+ if (DECL_IS_BUILTIN (x) && TREE_CODE (TREE_TYPE (x)) != ARRAY_TYPE)
{
if (TYPE_NAME (TREE_TYPE (x)) == 0)
TYPE_NAME (TREE_TYPE (x)) = x;
@@ -12024,7 +7470,12 @@ set_underlying_type (tree x)
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);
+
+ /* Mark the type as used only when its type decl is decorated
+ with attribute unused. */
+ if (lookup_attribute ("unused", DECL_ATTRIBUTES (x)))
+ TREE_USED (tt) = 1;
+
TREE_TYPE (x) = tt;
}
}
@@ -12047,182 +7498,6 @@ record_types_used_by_current_var_decl (tree decl)
}
}
-/* If DECL is a typedef that is declared in the current function,
- record it for the purpose of -Wunused-local-typedefs. */
-
-void
-record_locally_defined_typedef (tree decl)
-{
- struct c_language_function *l;
-
- if (!warn_unused_local_typedefs
- || cfun == NULL
- /* if this is not a locally defined typedef then we are not
- interested. */
- || !is_typedef_decl (decl)
- || !decl_function_context (decl))
- return;
-
- l = (struct c_language_function *) cfun->language;
- vec_safe_push (l->local_typedefs, decl);
-}
-
-/* If T is a TYPE_DECL declared locally, mark it as used. */
-
-void
-maybe_record_typedef_use (tree t)
-{
- if (!is_typedef_decl (t))
- return;
-
- TREE_USED (t) = true;
-}
-
-/* Warn if there are some unused locally defined typedefs in the
- current function. */
-
-void
-maybe_warn_unused_local_typedefs (void)
-{
- int i;
- tree decl;
- /* The number of times we have emitted -Wunused-local-typedefs
- warnings. If this is different from errorcount, that means some
- unrelated errors have been issued. In which case, we'll avoid
- emitting "unused-local-typedefs" warnings. */
- static int unused_local_typedefs_warn_count;
- struct c_language_function *l;
-
- if (cfun == NULL)
- return;
-
- if ((l = (struct c_language_function *) cfun->language) == NULL)
- return;
-
- if (warn_unused_local_typedefs
- && errorcount == unused_local_typedefs_warn_count)
- {
- FOR_EACH_VEC_SAFE_ELT (l->local_typedefs, i, decl)
- if (!TREE_USED (decl))
- warning_at (DECL_SOURCE_LOCATION (decl),
- OPT_Wunused_local_typedefs,
- "typedef %qD locally defined but not used", decl);
- unused_local_typedefs_warn_count = errorcount;
- }
-
- vec_free (l->local_typedefs);
-}
-
-/* Warn about boolean expression compared with an integer value different
- from true/false. Warns also e.g. about "(i1 == i2) == 2".
- LOC is the location of the comparison, CODE is its code, OP0 and OP1
- are the operands of the comparison. The caller must ensure that
- either operand is a boolean expression. */
-
-void
-maybe_warn_bool_compare (location_t loc, enum tree_code code, tree op0,
- tree op1)
-{
- if (TREE_CODE_CLASS (code) != tcc_comparison)
- return;
-
- tree f, cst;
- if (f = fold_for_warn (op0),
- TREE_CODE (f) == INTEGER_CST)
- cst = op0 = f;
- else if (f = fold_for_warn (op1),
- TREE_CODE (f) == INTEGER_CST)
- cst = op1 = f;
- else
- return;
-
- if (!integer_zerop (cst) && !integer_onep (cst))
- {
- int sign = (TREE_CODE (op0) == INTEGER_CST
- ? tree_int_cst_sgn (cst) : -tree_int_cst_sgn (cst));
- if (code == EQ_EXPR
- || ((code == GT_EXPR || code == GE_EXPR) && sign < 0)
- || ((code == LT_EXPR || code == LE_EXPR) && sign > 0))
- warning_at (loc, OPT_Wbool_compare, "comparison of constant %qE "
- "with boolean expression is always false", cst);
- else
- warning_at (loc, OPT_Wbool_compare, "comparison of constant %qE "
- "with boolean expression is always true", cst);
- }
- else if (integer_zerop (cst) || integer_onep (cst))
- {
- /* If the non-constant operand isn't of a boolean type, we
- don't want to warn here. */
- tree noncst = TREE_CODE (op0) == INTEGER_CST ? op1 : op0;
- /* Handle booleans promoted to integers. */
- if (CONVERT_EXPR_P (noncst)
- && TREE_TYPE (noncst) == integer_type_node
- && TREE_CODE (TREE_TYPE (TREE_OPERAND (noncst, 0))) == BOOLEAN_TYPE)
- /* Warn. */;
- else if (TREE_CODE (TREE_TYPE (noncst)) != BOOLEAN_TYPE
- && !truth_value_p (TREE_CODE (noncst)))
- return;
- /* Do some magic to get the right diagnostics. */
- bool flag = TREE_CODE (op0) == INTEGER_CST;
- flag = integer_zerop (cst) ? flag : !flag;
- if ((code == GE_EXPR && !flag) || (code == LE_EXPR && flag))
- warning_at (loc, OPT_Wbool_compare, "comparison of constant %qE "
- "with boolean expression is always true", cst);
- else if ((code == LT_EXPR && !flag) || (code == GT_EXPR && flag))
- warning_at (loc, OPT_Wbool_compare, "comparison of constant %qE "
- "with boolean expression is always false", cst);
- }
-}
-
-/* Warn if signed left shift overflows. We don't warn
- about left-shifting 1 into the sign bit in C++14; cf.
- <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3367.html#1457>
- LOC is a location of the shift; OP0 and OP1 are the operands.
- Return true if an overflow is detected, false otherwise. */
-
-bool
-maybe_warn_shift_overflow (location_t loc, tree op0, tree op1)
-{
- if (TREE_CODE (op0) != INTEGER_CST
- || TREE_CODE (op1) != INTEGER_CST)
- return false;
-
- tree type0 = TREE_TYPE (op0);
- unsigned int prec0 = TYPE_PRECISION (type0);
-
- /* Left-hand operand must be signed. */
- if (TYPE_UNSIGNED (type0))
- return false;
-
- unsigned int min_prec = (wi::min_precision (op0, SIGNED)
- + TREE_INT_CST_LOW (op1));
- /* Handle the case of left-shifting 1 into the sign bit.
- * However, shifting 1 _out_ of the sign bit, as in
- * INT_MIN << 1, is considered an overflow.
- */
- if (!tree_int_cst_sign_bit(op0) && min_prec == prec0 + 1)
- {
- /* Never warn for C++14 onwards. */
- if (cxx_dialect >= cxx14)
- return false;
- /* Otherwise only if -Wshift-overflow=2. But return
- true to signal an overflow for the sake of integer
- constant expressions. */
- if (warn_shift_overflow < 2)
- return true;
- }
-
- bool overflowed = min_prec > prec0;
- if (overflowed && c_inhibit_evaluation_warnings == 0)
- warning_at (loc, OPT_Wshift_overflow_,
- "result of %qE requires %u bits to represent, "
- "but %qT only has %u bits",
- build2_loc (loc, LSHIFT_EXPR, type0, op0, op1),
- min_prec, type0, prec0);
-
- return overflowed;
-}
-
/* 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. */
@@ -12283,6 +7558,18 @@ make_tree_vector_from_list (tree list)
return ret;
}
+/* Get a new tree vector of the values of a CONSTRUCTOR. */
+
+vec<tree, va_gc> *
+make_tree_vector_from_ctor (tree ctor)
+{
+ vec<tree,va_gc> *ret = make_tree_vector ();
+ vec_safe_reserve (ret, CONSTRUCTOR_NELTS (ctor));
+ for (unsigned i = 0; i < CONSTRUCTOR_NELTS (ctor); ++i)
+ ret->quick_push (CONSTRUCTOR_ELT (ctor, i)->value);
+ return ret;
+}
+
/* Get a new tree vector which is a copy of an existing one. */
vec<tree, va_gc> *
@@ -12316,6 +7603,7 @@ keyword_begins_type_specifier (enum rid keyword)
case RID_LONG:
case RID_SHORT:
case RID_SIGNED:
+ CASE_RID_FLOATN_NX:
case RID_DFLOAT32:
case RID_DFLOAT64:
case RID_DFLOAT128:
@@ -12446,66 +7734,34 @@ build_userdef_literal (tree suffix_id, tree value,
return literal;
}
-/* For vector[index], convert the vector to a
- pointer of the underlying type. Return true if the resulting
- ARRAY_REF should not be an lvalue. */
+/* For vector[index], convert the vector to an array of the underlying type.
+ Return true if the resulting ARRAY_REF should not be an lvalue. */
bool
-convert_vector_to_pointer_for_subscript (location_t loc,
- tree *vecp, tree index)
+convert_vector_to_array_for_subscript (location_t loc,
+ tree *vecp, tree index)
{
bool ret = false;
if (VECTOR_TYPE_P (TREE_TYPE (*vecp)))
{
tree type = TREE_TYPE (*vecp);
- tree type1;
ret = !lvalue_p (*vecp);
+
if (TREE_CODE (index) == INTEGER_CST)
if (!tree_fits_uhwi_p (index)
|| tree_to_uhwi (index) >= TYPE_VECTOR_SUBPARTS (type))
warning_at (loc, OPT_Warray_bounds, "index value is out of bound");
- if (ret)
- {
- tree tmp = create_tmp_var_raw (type);
- DECL_SOURCE_LOCATION (tmp) = loc;
- *vecp = c_save_expr (*vecp);
- if (TREE_CODE (*vecp) == C_MAYBE_CONST_EXPR)
- {
- bool non_const = C_MAYBE_CONST_EXPR_NON_CONST (*vecp);
- *vecp = C_MAYBE_CONST_EXPR_EXPR (*vecp);
- *vecp
- = c_wrap_maybe_const (build4 (TARGET_EXPR, type, tmp,
- *vecp, NULL_TREE, NULL_TREE),
- non_const);
- }
- else
- *vecp = build4 (TARGET_EXPR, type, tmp, *vecp,
- NULL_TREE, NULL_TREE);
- SET_EXPR_LOCATION (*vecp, loc);
- c_common_mark_addressable_vec (tmp);
- }
- else
- c_common_mark_addressable_vec (*vecp);
- type = build_qualified_type (TREE_TYPE (type), TYPE_QUALS (type));
- type1 = build_pointer_type (TREE_TYPE (*vecp));
- bool ref_all = TYPE_REF_CAN_ALIAS_ALL (type1);
- if (!ref_all
- && !DECL_P (*vecp))
- {
- /* If the original vector isn't declared may_alias and it
- isn't a bare vector look if the subscripting would
- alias the vector we subscript, and if not, force ref-all. */
- alias_set_type vecset = get_alias_set (*vecp);
- alias_set_type sset = get_alias_set (type);
- if (!alias_sets_must_conflict_p (sset, vecset)
- && !alias_set_subset_of (sset, vecset))
- ref_all = true;
- }
- type = build_pointer_type_for_mode (type, ptr_mode, ref_all);
- *vecp = build1 (ADDR_EXPR, type1, *vecp);
- *vecp = convert (type, *vecp);
+ /* We are building an ARRAY_REF so mark the vector as addressable
+ to not run into the gimplifiers premature setting of DECL_GIMPLE_REG_P
+ for function parameters. */
+ c_common_mark_addressable_vec (*vecp);
+
+ *vecp = build1 (VIEW_CONVERT_EXPR,
+ build_array_type_nelts (TREE_TYPE (type),
+ TYPE_VECTOR_SUBPARTS (type)),
+ *vecp);
}
return ret;
}
@@ -12549,7 +7805,7 @@ scalar_to_vector (location_t loc, enum tree_code code, tree op0, tree op1,
case BIT_XOR_EXPR:
case BIT_AND_EXPR:
integer_only_op = true;
- /* ... fall through ... */
+ /* fall through */
case VEC_COND_EXPR:
@@ -12612,6 +7868,22 @@ scalar_to_vector (location_t loc, enum tree_code code, tree op0, tree op1,
return stv_nothing;
}
+/* Return the alignment of std::max_align_t.
+
+ [support.types.layout] The type max_align_t is a POD type whose alignment
+ requirement is at least as great as that of every scalar type, and whose
+ alignment requirement is supported in every context. */
+
+unsigned
+max_align_t_align ()
+{
+ unsigned int max_align = MAX (TYPE_ALIGN (long_long_integer_type_node),
+ TYPE_ALIGN (long_double_type_node));
+ if (float128_type_node != NULL_TREE)
+ max_align = MAX (max_align, TYPE_ALIGN (float128_type_node));
+ return max_align;
+}
+
/* Return true iff ALIGN is an integral constant that is a fundamental
alignment, as defined by [basic.align] in the c++-11
specifications.
@@ -12620,14 +7892,12 @@ scalar_to_vector (location_t loc, enum tree_code code, tree op0, tree op1,
[A fundamental alignment is represented by an alignment less than or
equal to the greatest alignment supported by the implementation
- in all contexts, which is equal to
- alignof(max_align_t)]. */
+ in all contexts, which is equal to alignof(max_align_t)]. */
bool
-cxx_fundamental_alignment_p (unsigned align)
+cxx_fundamental_alignment_p (unsigned align)
{
- return (align <= MAX (TYPE_ALIGN (long_long_integer_type_node),
- TYPE_ALIGN (long_double_type_node)));
+ return (align <= max_align_t_align ());
}
/* Return true if T is a pointer to a zero-sized aggregate. */
@@ -12646,6 +7916,7 @@ pointer_to_zero_sized_aggr_p (tree t)
issues an error pointing to the location LOC.
Returns true when the expression has been diagnosed and false
otherwise. */
+
bool
reject_gcc_builtin (const_tree expr, location_t loc /* = UNKNOWN_LOCATION */)
{
@@ -12678,47 +7949,6 @@ reject_gcc_builtin (const_tree expr, location_t loc /* = UNKNOWN_LOCATION */)
return false;
}
-/* If we're creating an if-else-if condition chain, first see if we
- already have this COND in the CHAIN. If so, warn and don't add COND
- into the vector, otherwise add the COND there. LOC is the location
- of COND. */
-
-void
-warn_duplicated_cond_add_or_warn (location_t loc, tree cond, vec<tree> **chain)
-{
- /* No chain has been created yet. Do nothing. */
- if (*chain == NULL)
- return;
-
- if (TREE_SIDE_EFFECTS (cond))
- {
- /* Uh-oh! This condition has a side-effect, thus invalidates
- the whole chain. */
- delete *chain;
- *chain = NULL;
- return;
- }
-
- unsigned int ix;
- tree t;
- bool found = false;
- FOR_EACH_VEC_ELT (**chain, ix, t)
- if (operand_equal_p (cond, t, 0))
- {
- if (warning_at (loc, OPT_Wduplicated_cond,
- "duplicated %<if%> condition"))
- inform (EXPR_LOCATION (t), "previously used here");
- found = true;
- break;
- }
-
- if (!found
- && !CONSTANT_CLASS_P (cond)
- /* Don't infinitely grow the chain. */
- && (*chain)->length () < 512)
- (*chain)->safe_push (cond);
-}
-
/* Check if array size calculations overflow or if the array covers more
than half of the address space. Return true if the size of the array
is valid, false otherwise. TYPE is the type of the array and NAME is
@@ -12741,4 +7971,135 @@ valid_array_size_p (location_t loc, tree type, tree name)
return true;
}
+/* Read SOURCE_DATE_EPOCH from environment to have a deterministic
+ timestamp to replace embedded current dates to get reproducible
+ results. Returns -1 if SOURCE_DATE_EPOCH is not defined. */
+
+time_t
+cb_get_source_date_epoch (cpp_reader *pfile ATTRIBUTE_UNUSED)
+{
+ char *source_date_epoch;
+ int64_t epoch;
+ char *endptr;
+
+ source_date_epoch = getenv ("SOURCE_DATE_EPOCH");
+ if (!source_date_epoch)
+ return (time_t) -1;
+
+ errno = 0;
+#if defined(INT64_T_IS_LONG)
+ epoch = strtol (source_date_epoch, &endptr, 10);
+#else
+ epoch = strtoll (source_date_epoch, &endptr, 10);
+#endif
+ if (errno != 0 || endptr == source_date_epoch || *endptr != '\0'
+ || epoch < 0 || epoch > MAX_SOURCE_DATE_EPOCH)
+ {
+ error_at (input_location, "environment variable SOURCE_DATE_EPOCH must "
+ "expand to a non-negative integer less than or equal to %wd",
+ MAX_SOURCE_DATE_EPOCH);
+ return (time_t) -1;
+ }
+
+ return (time_t) epoch;
+}
+
+/* Callback for libcpp for offering spelling suggestions for misspelled
+ directives. GOAL is an unrecognized string; CANDIDATES is a
+ NULL-terminated array of candidate strings. Return the closest
+ match to GOAL within CANDIDATES, or NULL if none are good
+ suggestions. */
+
+const char *
+cb_get_suggestion (cpp_reader *, const char *goal,
+ const char *const *candidates)
+{
+ best_match<const char *, const char *> bm (goal);
+ while (*candidates)
+ bm.consider (*candidates++);
+ return bm.get_best_meaningful_candidate ();
+}
+
+/* Return the latice point which is the wider of the two FLT_EVAL_METHOD
+ modes X, Y. This isn't just >, as the FLT_EVAL_METHOD values added
+ by C TS 18661-3 for interchange types that are computed in their
+ native precision are larger than the C11 values for evaluating in the
+ precision of float/double/long double. If either mode is
+ FLT_EVAL_METHOD_UNPREDICTABLE, return that. */
+
+enum flt_eval_method
+excess_precision_mode_join (enum flt_eval_method x,
+ enum flt_eval_method y)
+{
+ if (x == FLT_EVAL_METHOD_UNPREDICTABLE
+ || y == FLT_EVAL_METHOD_UNPREDICTABLE)
+ return FLT_EVAL_METHOD_UNPREDICTABLE;
+
+ /* GCC only supports one interchange type right now, _Float16. If
+ we're evaluating _Float16 in 16-bit precision, then flt_eval_method
+ will be FLT_EVAL_METHOD_PROMOTE_TO_FLOAT16. */
+ if (x == FLT_EVAL_METHOD_PROMOTE_TO_FLOAT16)
+ return y;
+ if (y == FLT_EVAL_METHOD_PROMOTE_TO_FLOAT16)
+ return x;
+
+ /* Other values for flt_eval_method are directly comparable, and we want
+ the maximum. */
+ return MAX (x, y);
+}
+
+/* Return the value that should be set for FLT_EVAL_METHOD in the
+ context of ISO/IEC TS 18861-3.
+
+ This relates to the effective excess precision seen by the user,
+ which is the join point of the precision the target requests for
+ -fexcess-precision={standard,fast} and the implicit excess precision
+ the target uses. */
+
+static enum flt_eval_method
+c_ts18661_flt_eval_method (void)
+{
+ enum flt_eval_method implicit
+ = targetm.c.excess_precision (EXCESS_PRECISION_TYPE_IMPLICIT);
+
+ enum excess_precision_type flag_type
+ = (flag_excess_precision_cmdline == EXCESS_PRECISION_STANDARD
+ ? EXCESS_PRECISION_TYPE_STANDARD
+ : EXCESS_PRECISION_TYPE_FAST);
+
+ enum flt_eval_method requested
+ = targetm.c.excess_precision (flag_type);
+
+ return excess_precision_mode_join (implicit, requested);
+}
+
+/* As c_cpp_ts18661_flt_eval_method, but clamps the expected values to
+ those that were permitted by C11. That is to say, eliminates
+ FLT_EVAL_METHOD_PROMOTE_TO_FLOAT16. */
+
+static enum flt_eval_method
+c_c11_flt_eval_method (void)
+{
+ return excess_precision_mode_join (c_ts18661_flt_eval_method (),
+ FLT_EVAL_METHOD_PROMOTE_TO_FLOAT);
+}
+
+/* Return the value that should be set for FLT_EVAL_METHOD.
+ MAYBE_C11_ONLY_P is TRUE if we should check
+ FLAG_PERMITTED_EVAL_METHODS as to whether we should limit the possible
+ values we can return to those from C99/C11, and FALSE otherwise.
+ See the comments on c_ts18661_flt_eval_method for what value we choose
+ to set here. */
+
+int
+c_flt_eval_method (bool maybe_c11_only_p)
+{
+ if (maybe_c11_only_p
+ && flag_permitted_flt_eval_methods
+ == PERMITTED_FLT_EVAL_METHODS_C11)
+ return c_c11_flt_eval_method ();
+ else
+ return c_ts18661_flt_eval_method ();
+}
+
#include "gt-c-family-c-common.h"
diff --git a/gcc/c-family/c-common.def b/gcc/c-family/c-common.def
index 1d3ee5316b..aeec271453 100644
--- a/gcc/c-family/c-common.def
+++ b/gcc/c-family/c-common.def
@@ -1,7 +1,7 @@
/* 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-2016 Free Software Foundation, Inc.
+ Copyright (C) 1987-2017 Free Software Foundation, Inc.
Written by Benjamin Chelf <chelf@codesourcery.com>
This file is part of GCC.
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index dd74d0dd62..b933342043 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1,5 +1,5 @@
/* Definitions for c-common.c.
- Copyright (C) 1987-2016 Free Software Foundation, Inc.
+ Copyright (C) 1987-2017 Free Software Foundation, Inc.
This file is part of GCC.
@@ -102,8 +102,31 @@ enum rid
RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL, RID_CHOOSE_EXPR,
RID_TYPES_COMPATIBLE_P, RID_BUILTIN_COMPLEX, RID_BUILTIN_SHUFFLE,
RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128,
+
+ /* TS 18661-3 keywords, in the same sequence as the TI_* values. */
+ RID_FLOAT16,
+ RID_FLOATN_NX_FIRST = RID_FLOAT16,
+ RID_FLOAT32,
+ RID_FLOAT64,
+ RID_FLOAT128,
+ RID_FLOAT32X,
+ RID_FLOAT64X,
+ RID_FLOAT128X,
+#define CASE_RID_FLOATN_NX \
+ case RID_FLOAT16: case RID_FLOAT32: case RID_FLOAT64: case RID_FLOAT128: \
+ case RID_FLOAT32X: case RID_FLOAT64X: case RID_FLOAT128X
+
RID_FRACT, RID_ACCUM, RID_AUTO_TYPE, RID_BUILTIN_CALL_WITH_STATIC_CHAIN,
+ /* "__GIMPLE", for the GIMPLE-parsing extension to the C frontend. */
+ RID_GIMPLE,
+
+ /* "__PHI", for parsing PHI function in GIMPLE FE. */
+ RID_PHI,
+
+ /* "__RTL", for the RTL-parsing extension to the C frontend. */
+ RID_RTL,
+
/* C11 */
RID_ALIGNAS, RID_GENERIC,
@@ -132,13 +155,15 @@ enum rid
RID_CONSTCAST, RID_DYNCAST, RID_REINTCAST, RID_STATCAST,
/* C++ extensions */
- RID_BASES, RID_DIRECT_BASES,
+ RID_ADDRESSOF, RID_BASES,
+ RID_BUILTIN_LAUNDER, RID_DIRECT_BASES,
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_CLASS,
+ RID_HAS_TRIVIAL_DESTRUCTOR, RID_HAS_UNIQUE_OBJ_REPRESENTATIONS,
+ RID_HAS_VIRTUAL_DESTRUCTOR,
+ RID_IS_ABSTRACT, RID_IS_AGGREGATE,
+ RID_IS_BASE_OF, RID_IS_CLASS,
RID_IS_EMPTY, RID_IS_ENUM,
RID_IS_FINAL, RID_IS_LITERAL_TYPE,
RID_IS_POD, RID_IS_POLYMORPHIC,
@@ -782,17 +807,19 @@ extern const char *fname_as_string (int);
extern tree fname_decl (location_t, unsigned, tree);
extern int check_user_alignment (const_tree, bool);
-extern void check_function_arguments (location_t loc, const_tree, int, tree *);
+extern bool check_function_arguments (location_t loc, const_tree, const_tree,
+ int, 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 bool check_builtin_function_arguments (location_t, vec<location_t>,
+ tree, int, tree *);
extern void check_function_format (tree, int, tree *);
+extern bool attribute_fallthrough_p (tree);
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 bool default_handle_c_option (size_t, const char *, int);
@@ -819,21 +846,7 @@ extern tree c_alignof_expr (location_t, tree);
NOP_EXPR is used as a special case (see truthvalue_conversion). */
extern void binary_op_error (rich_location *, 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 sizeof_pointer_memaccess_warning (location_t *, tree,
- vec<tree, va_gc> *, tree *,
- bool (*) (tree, tree));
-extern void warnings_for_convert_and_check (location_t, tree, tree, tree);
extern tree convert_and_check (location_t, tree, tree);
-extern void overflow_warning (location_t, tree);
-extern bool warn_if_unused_value (const_tree, location_t);
-extern void warn_logical_operator (location_t, enum tree_code, tree,
- enum tree_code, tree, enum tree_code, tree);
-extern void warn_logical_not_parentheses (location_t, enum tree_code, tree);
-extern void warn_tautological_cmp (location_t, enum tree_code, tree, tree);
-extern void check_main_parameter_types (tree decl);
extern bool c_determine_visibility (tree);
extern bool vector_types_compatible_elements_p (tree, tree);
extern void mark_valid_location_for_stdc_pragma (bool);
@@ -846,8 +859,13 @@ 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);
+extern unsigned max_align_t_align (void);
extern bool cxx_fundamental_alignment_p (unsigned);
extern bool pointer_to_zero_sized_aggr_p (tree);
+extern bool bool_promoted_to_int_p (tree);
+extern tree fold_for_warn (tree);
+extern tree c_common_get_narrower (tree, int *);
+extern bool get_nonnull_operand (tree, unsigned HOST_WIDE_INT *);
#define c_sizeof(LOC, T) c_sizeof_or_alignof_type (LOC, T, true, false, 1)
#define c_alignof(LOC, T) c_sizeof_or_alignof_type (LOC, T, false, false, 1)
@@ -901,8 +919,6 @@ extern void c_parse_file (void);
extern void c_parse_final_cleanups (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
@@ -944,7 +960,7 @@ 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_unary_op (location_t, enum tree_code, tree, bool);
extern tree build_binary_op (location_t, enum tree_code, tree, tree, int);
extern tree perform_integral_promotions (tree);
@@ -968,9 +984,6 @@ extern int case_compare (splay_tree_key, splay_tree_key);
extern tree c_add_case_label (location_t, splay_tree, tree, tree, tree, tree,
bool *);
-extern void c_do_switch_warnings (splay_tree, location_t, tree, tree, bool,
- bool);
-
extern tree build_function_call (location_t, tree, tree);
extern tree build_function_call_vec (location_t, vec<location_t>, tree,
@@ -986,6 +999,18 @@ extern tree lookup_label (tree);
extern tree lookup_name (tree);
extern bool lvalue_p (const_tree);
+enum lookup_name_fuzzy_kind {
+ /* Names of types. */
+ FUZZY_LOOKUP_TYPENAME,
+
+ /* Names of function decls. */
+ FUZZY_LOOKUP_FUNCTION_NAME,
+
+ /* Any name. */
+ FUZZY_LOOKUP_NAME
+};
+extern const char *lookup_name_fuzzy (tree, enum lookup_name_fuzzy_kind);
+
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 tree c_build_vec_perm_expr (location_t, tree, tree, tree, bool = true);
@@ -1031,59 +1056,46 @@ extern void verify_sequence_points (tree);
extern tree fold_offsetof_1 (tree, tree_code ctx = ERROR_MARK);
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 (location_t, 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 (location_t, tree);
-extern void warn_about_parentheses (location_t,
- 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_unused_parameter (tree);
-extern void do_warn_double_promotion (tree, tree, tree, const char *,
- location_t);
extern void set_underlying_type (tree);
extern void record_types_used_by_current_var_decl (tree);
-extern void record_locally_defined_typedef (tree);
-extern void maybe_record_typedef_use (tree);
-extern void maybe_warn_unused_local_typedefs (void);
-extern void maybe_warn_bool_compare (location_t, enum tree_code, tree, tree);
-extern bool maybe_warn_shift_overflow (location_t, tree, tree);
extern vec<tree, va_gc> *make_tree_vector (void);
extern void release_tree_vector (vec<tree, va_gc> *);
extern vec<tree, va_gc> *make_tree_vector_single (tree);
extern vec<tree, va_gc> *make_tree_vector_from_list (tree);
+extern vec<tree, va_gc> *make_tree_vector_from_ctor (tree);
extern vec<tree, va_gc> *make_tree_vector_copy (const vec<tree, va_gc> *);
/* Used for communication between c_common_type_for_mode and
c_register_builtin_type. */
extern GTY(()) tree registered_builtin_types;
+/* Read SOURCE_DATE_EPOCH from environment to have a deterministic
+ timestamp to replace embedded current dates to get reproducible
+ results. Returns -1 if SOURCE_DATE_EPOCH is not defined. */
+extern time_t cb_get_source_date_epoch (cpp_reader *pfile);
+
+/* The value (as a unix timestamp) corresponds to date
+ "Dec 31 9999 23:59:59 UTC", which is the latest date that __DATE__ and
+ __TIME__ can store. */
+#define MAX_SOURCE_DATE_EPOCH HOST_WIDE_INT_C (253402300799)
+
+/* Callback for libcpp for offering spelling suggestions for misspelled
+ directives. */
+extern const char *cb_get_suggestion (cpp_reader *, const char *,
+ const char *const *);
+
+extern GTY(()) string_concat_db *g_string_concat_db;
+
+class substring_loc;
+extern const char *c_get_substring_location (const substring_loc &substr_loc,
+ location_t *out_loc);
+
/* In c-gimplify.c */
extern void c_genericize (tree);
extern int c_gimplify_expr (tree *, gimple_seq *, gimple_seq *);
@@ -1259,6 +1271,15 @@ enum c_omp_clause_split
C_OMP_CLAUSE_SPLIT_TASKLOOP = C_OMP_CLAUSE_SPLIT_FOR
};
+enum c_omp_region_type
+{
+ C_ORT_OMP = 1 << 0,
+ C_ORT_CILK = 1 << 1,
+ C_ORT_ACC = 1 << 2,
+ C_ORT_DECLARE_SIMD = 1 << 3,
+ C_ORT_OMP_DECLARE_SIMD = C_ORT_OMP | C_ORT_DECLARE_SIMD
+};
+
extern tree c_finish_omp_master (location_t, tree);
extern tree c_finish_omp_taskgroup (location_t, tree);
extern tree c_finish_omp_critical (location_t, tree, tree, tree);
@@ -1303,8 +1324,6 @@ c_tree_chain_next (tree t)
#define TM_STMT_ATTR_ATOMIC 4
#define TM_STMT_ATTR_RELAXED 8
-extern int parse_tm_stmt_attr (tree, int);
-
/* Mask used by tm_attr_to_mask and tm_mask_to_attr. Note that these
are ordered specifically such that more restrictive attributes are
at lower bit positions. This fact is known by the C++ tm attribute
@@ -1316,10 +1335,6 @@ extern int parse_tm_stmt_attr (tree, int);
#define TM_ATTR_IRREVOCABLE 8
#define TM_ATTR_MAY_CANCEL_OUTER 16
-extern int tm_attr_to_mask (tree);
-extern tree tm_mask_to_attr (int);
-extern tree find_tm_attribute (tree);
-
/* A suffix-identifier value doublet that represents user-defined literals
for C++-0x. */
enum overflow_type {
@@ -1355,7 +1370,7 @@ extern tree build_userdef_literal (tree suffix_id, tree value,
enum overflow_type overflow,
tree num_string);
-extern bool convert_vector_to_pointer_for_subscript (location_t, tree *, tree);
+extern bool convert_vector_to_array_for_subscript (location_t, tree *, tree);
/* Possibe cases of scalar_to_vector conversion. */
enum stv_conv {
@@ -1369,7 +1384,6 @@ extern enum stv_conv scalar_to_vector (location_t loc, enum tree_code code,
tree op0, tree op1, bool);
/* In c-cilkplus.c */
-extern tree c_finish_cilk_clauses (tree);
extern tree c_validate_cilk_plus_loop (tree *, int *, void *);
extern bool c_check_cilk_loop (location_t, tree);
@@ -1464,7 +1478,89 @@ extern tree cilk_for_number_of_iterations (tree);
extern bool check_no_cilk (tree, const char *, const char *,
location_t loc = UNKNOWN_LOCATION);
extern bool reject_gcc_builtin (const_tree, location_t = UNKNOWN_LOCATION);
-extern void warn_duplicated_cond_add_or_warn (location_t, tree, vec<tree> **);
extern bool valid_array_size_p (location_t, tree, tree);
+extern bool cilk_ignorable_spawn_rhs_op (tree);
+extern bool cilk_recognize_spawn (tree, tree *);
+
+/* In c-warn.c. */
+extern void constant_expression_warning (tree);
+extern void constant_expression_error (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 warn_tautological_cmp (location_t, enum tree_code, tree, tree);
+extern void warn_logical_not_parentheses (location_t, enum tree_code, tree,
+ tree);
+extern bool warn_if_unused_value (const_tree, location_t);
+extern bool strict_aliasing_warning (tree, tree, tree);
+extern void sizeof_pointer_memaccess_warning (location_t *, tree,
+ vec<tree, va_gc> *, tree *,
+ bool (*) (tree, tree));
+extern void check_main_parameter_types (tree decl);
+extern void warnings_for_convert_and_check (location_t, tree, tree, tree);
+extern void c_do_switch_warnings (splay_tree, location_t, tree, tree, bool,
+ bool);
+extern void warn_for_omitted_condop (location_t, tree);
+extern void warn_for_restrict (unsigned, tree *, unsigned);
+
+/* Places where an lvalue, or modifiable lvalue, may be required.
+ Used to select diagnostic messages in lvalue_error and
+ readonly_error. */
+enum lvalue_use {
+ lv_assign,
+ lv_increment,
+ lv_decrement,
+ lv_addressof,
+ lv_asm
+};
+
+extern void lvalue_error (location_t, enum lvalue_use);
+extern void invalid_indirection_error (location_t, tree, ref_operator);
+extern void readonly_error (location_t, tree, enum lvalue_use);
+extern void warn_array_subscript_with_type_char (location_t, tree);
+extern void warn_about_parentheses (location_t,
+ 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_memset (location_t, tree, tree, int);
+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 do_warn_unused_parameter (tree);
+extern void record_locally_defined_typedef (tree);
+extern void maybe_record_typedef_use (tree);
+extern void maybe_warn_unused_local_typedefs (void);
+extern void maybe_warn_bool_compare (location_t, enum tree_code, tree, tree);
+extern bool maybe_warn_shift_overflow (location_t, tree, tree);
+extern void warn_duplicated_cond_add_or_warn (location_t, tree, vec<tree> **);
+extern bool diagnose_mismatched_attributes (tree, tree);
+extern tree do_warn_duplicated_branches_r (tree *, int *, void *);
+
+/* In c-attribs.c. */
+extern bool attribute_takes_identifier_p (const_tree);
+extern tree handle_unused_attribute (tree *, tree, tree, int, bool *);
+extern int parse_tm_stmt_attr (tree, int);
+extern int tm_attr_to_mask (tree);
+extern tree tm_mask_to_attr (int);
+extern tree find_tm_attribute (tree);
+
+extern enum flt_eval_method
+excess_precision_mode_join (enum flt_eval_method, enum flt_eval_method);
+
+extern int c_flt_eval_method (bool ts18661_p);
+
+#if CHECKING_P
+namespace selftest {
+ extern void c_format_c_tests (void);
+ extern void run_c_tests (void);
+} // namespace selftest
+#endif /* #if CHECKING_P */
+
#endif /* ! GCC_C_COMMON_H */
diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c
index 3d4587e6db..083d5fdf4c 100644
--- a/gcc/c-family/c-cppbuiltin.c
+++ b/gcc/c-family/c-cppbuiltin.c
@@ -1,5 +1,5 @@
/* Define builtin-in macros for the C family front ends.
- Copyright (C) 2002-2016 Free Software Foundation, Inc.
+ Copyright (C) 2002-2017 Free Software Foundation, Inc.
This file is part of GCC.
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "target.h"
#include "c-common.h"
+#include "memmodel.h"
#include "tm_p.h" /* For TARGET_CPU_CPP_BUILTINS & friends. */
#include "stringpool.h"
#include "stor-layout.h"
@@ -54,6 +55,7 @@ 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_width (const char *, tree, tree);
static void builtin_define_float_constants (const char *,
const char *,
const char *,
@@ -125,7 +127,7 @@ builtin_define_float_constants (const char *name_prefix,
const double log10_2 = .30102999566398119521;
double log10_b;
const struct real_format *fmt;
- const struct real_format *ldfmt;
+ const struct real_format *widefmt;
char name[64], buf[128];
int dig, min_10_exp, max_10_exp;
@@ -134,8 +136,20 @@ builtin_define_float_constants (const char *name_prefix,
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);
+ widefmt = REAL_MODE_FORMAT (TYPE_MODE (long_double_type_node));
+ gcc_assert (widefmt->b != 10);
+ for (int i = 0; i < NUM_FLOATN_NX_TYPES; i++)
+ {
+ tree wtype = FLOATN_NX_TYPE_NODE (i);
+ if (wtype != NULL_TREE)
+ {
+ const struct real_format *wfmt
+ = REAL_MODE_FORMAT (TYPE_MODE (wtype));
+ gcc_assert (wfmt->b != 10);
+ if (wfmt->p > widefmt->p)
+ widefmt = wfmt;
+ }
+ }
/* The radix of the exponent representation. */
if (type == float_type_node)
@@ -219,7 +233,7 @@ builtin_define_float_constants (const char *name_prefix,
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;
+ = 1 + (fmt->p < widefmt->p ? widefmt->p : fmt->p) * log10_b;
decimal_dig = d_decimal_dig;
if (decimal_dig < d_decimal_dig)
decimal_dig++;
@@ -231,13 +245,12 @@ builtin_define_float_constants (const char *name_prefix,
if (type_decimal_dig < type_d_decimal_dig)
type_decimal_dig++;
}
+ /* Define __DECIMAL_DIG__ to the value for long double to be
+ compatible with C99 and C11; see DR#501 and N2108. */
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);
- }
+ builtin_define_with_int_value ("__DECIMAL_DIG__", type_decimal_dig);
+ 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
@@ -289,7 +302,7 @@ builtin_define_float_constants (const char *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)))
+ if (mode_has_fma (TYPE_MODE (type)) && fma_suffix != NULL)
{
sprintf (name, "__FP_FAST_FMA%s", fma_suffix);
builtin_define_with_int_value (name, 1);
@@ -423,9 +436,15 @@ builtin_define_stdint_macros (void)
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);
+ builtin_define_type_width ("__INTMAX_WIDTH__", intmax_type_node,
+ uintmax_type_node);
if (sig_atomic_type_node)
- builtin_define_type_minmax ("__SIG_ATOMIC_MIN__", "__SIG_ATOMIC_MAX__",
- sig_atomic_type_node);
+ {
+ builtin_define_type_minmax ("__SIG_ATOMIC_MIN__", "__SIG_ATOMIC_MAX__",
+ sig_atomic_type_node);
+ builtin_define_type_width ("__SIG_ATOMIC_WIDTH__", sig_atomic_type_node,
+ NULL_TREE);
+ }
if (int8_type_node)
builtin_define_type_max ("__INT8_MAX__", int8_type_node);
if (int16_type_node)
@@ -446,21 +465,32 @@ builtin_define_stdint_macros (void)
{
builtin_define_type_max ("__INT_LEAST8_MAX__", int_least8_type_node);
builtin_define_constants ("__INT8_C", int_least8_type_node);
+ builtin_define_type_width ("__INT_LEAST8_WIDTH__", int_least8_type_node,
+ uint_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);
+ builtin_define_type_width ("__INT_LEAST16_WIDTH__",
+ int_least16_type_node,
+ uint_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);
+ builtin_define_type_width ("__INT_LEAST32_WIDTH__",
+ int_least32_type_node,
+ uint_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);
+ builtin_define_type_width ("__INT_LEAST64_WIDTH__",
+ int_least64_type_node,
+ uint_least64_type_node);
}
if (uint_least8_type_node)
{
@@ -483,13 +513,29 @@ builtin_define_stdint_macros (void)
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);
+ {
+ builtin_define_type_max ("__INT_FAST8_MAX__", int_fast8_type_node);
+ builtin_define_type_width ("__INT_FAST8_WIDTH__", int_fast8_type_node,
+ uint_fast8_type_node);
+ }
if (int_fast16_type_node)
- builtin_define_type_max ("__INT_FAST16_MAX__", int_fast16_type_node);
+ {
+ builtin_define_type_max ("__INT_FAST16_MAX__", int_fast16_type_node);
+ builtin_define_type_width ("__INT_FAST16_WIDTH__", int_fast16_type_node,
+ uint_fast16_type_node);
+ }
if (int_fast32_type_node)
- builtin_define_type_max ("__INT_FAST32_MAX__", int_fast32_type_node);
+ {
+ builtin_define_type_max ("__INT_FAST32_MAX__", int_fast32_type_node);
+ builtin_define_type_width ("__INT_FAST32_WIDTH__", int_fast32_type_node,
+ uint_fast32_type_node);
+ }
if (int_fast64_type_node)
- builtin_define_type_max ("__INT_FAST64_MAX__", int_fast64_type_node);
+ {
+ builtin_define_type_max ("__INT_FAST64_MAX__", int_fast64_type_node);
+ builtin_define_type_width ("__INT_FAST64_WIDTH__", int_fast64_type_node,
+ uint_fast64_type_node);
+ }
if (uint_fast8_type_node)
builtin_define_type_max ("__UINT_FAST8_MAX__", uint_fast8_type_node);
if (uint_fast16_type_node)
@@ -499,7 +545,11 @@ builtin_define_stdint_macros (void)
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);
+ {
+ builtin_define_type_max ("__INTPTR_MAX__", intptr_type_node);
+ builtin_define_type_width ("__INTPTR_WIDTH__", intptr_type_node,
+ uintptr_type_node);
+ }
if (uintptr_type_node)
builtin_define_type_max ("__UINTPTR_MAX__", uintptr_type_node);
}
@@ -677,6 +727,31 @@ cpp_atomic_builtins (cpp_reader *pfile)
(have_swap[psize]? 2 : 1));
}
+/* Return TRUE if the implicit excess precision in which the back-end will
+ compute floating-point calculations is not more than the explicit
+ excess precision that the front-end will apply under
+ -fexcess-precision=[standard|fast].
+
+ More intuitively, return TRUE if the excess precision proposed by the
+ front-end is the excess precision that will actually be used. */
+
+static bool
+c_cpp_flt_eval_method_iec_559 (void)
+{
+ enum excess_precision_type front_end_ept
+ = (flag_excess_precision_cmdline == EXCESS_PRECISION_STANDARD
+ ? EXCESS_PRECISION_TYPE_STANDARD
+ : EXCESS_PRECISION_TYPE_FAST);
+
+ enum flt_eval_method back_end
+ = targetm.c.excess_precision (EXCESS_PRECISION_TYPE_IMPLICIT);
+
+ enum flt_eval_method front_end
+ = targetm.c.excess_precision (front_end_ept);
+
+ return excess_precision_mode_join (front_end, back_end) == front_end;
+}
+
/* Return the value for __GCC_IEC_559. */
static int
cpp_iec_559_value (void)
@@ -719,16 +794,17 @@ cpp_iec_559_value (void)
|| !dfmt->has_signed_zero)
ret = 0;
- /* In strict C standards conformance mode, consider unpredictable
- excess precision to mean lack of IEEE 754 support. The same
- applies to unpredictable contraction. For C++, and outside
- strict conformance mode, do not consider these options to mean
- lack of IEEE 754 support. */
+ /* In strict C standards conformance mode, consider a back-end providing
+ more implicit excess precision than the explicit excess precision
+ the front-end options would require to mean a lack of IEEE 754
+ support. For C++, and outside strict conformance mode, do not consider
+ this to mean a lack of IEEE 754 support. */
+
if (flag_iso
&& !c_dialect_cxx ()
- && TARGET_FLT_EVAL_METHOD != 0
- && flag_excess_precision_cmdline != EXCESS_PRECISION_STANDARD)
+ && !c_cpp_flt_eval_method_iec_559 ())
ret = 0;
+
if (flag_iso
&& !c_dialect_cxx ()
&& flag_fp_contract_mode == FP_CONTRACT_FAST)
@@ -853,7 +929,10 @@ c_cpp_builtins (cpp_reader *pfile)
cpp_define (pfile, "__cpp_initializer_lists=200806");
cpp_define (pfile, "__cpp_delegating_constructors=200604");
cpp_define (pfile, "__cpp_nsdmi=200809");
- cpp_define (pfile, "__cpp_inheriting_constructors=200802");
+ if (!flag_new_inheriting_ctors)
+ cpp_define (pfile, "__cpp_inheriting_constructors=200802");
+ else
+ cpp_define (pfile, "__cpp_inheriting_constructors=201511");
cpp_define (pfile, "__cpp_ref_qualifiers=200710");
cpp_define (pfile, "__cpp_alias_templates=200704");
}
@@ -863,7 +942,8 @@ c_cpp_builtins (cpp_reader *pfile)
cpp_define (pfile, "__cpp_return_type_deduction=201304");
cpp_define (pfile, "__cpp_init_captures=201304");
cpp_define (pfile, "__cpp_generic_lambdas=201304");
- cpp_define (pfile, "__cpp_constexpr=201304");
+ if (cxx_dialect <= cxx14)
+ cpp_define (pfile, "__cpp_constexpr=201304");
cpp_define (pfile, "__cpp_decltype_auto=201304");
cpp_define (pfile, "__cpp_aggregate_nsdmi=201304");
cpp_define (pfile, "__cpp_variable_templates=201304");
@@ -880,17 +960,33 @@ c_cpp_builtins (cpp_reader *pfile)
cpp_define (pfile, "__cpp_fold_expressions=201603");
cpp_define (pfile, "__cpp_nontype_template_args=201411");
cpp_define (pfile, "__cpp_range_based_for=201603");
+ cpp_define (pfile, "__cpp_constexpr=201603");
+ cpp_define (pfile, "__cpp_if_constexpr=201606");
+ cpp_define (pfile, "__cpp_capture_star_this=201603");
+ cpp_define (pfile, "__cpp_inline_variables=201606");
+ cpp_define (pfile, "__cpp_aggregate_bases=201603");
+ cpp_define (pfile, "__cpp_deduction_guides=201606");
+ cpp_define (pfile, "__cpp_noexcept_function_type=201510");
+ cpp_define (pfile, "__cpp_template_auto=201606");
+ cpp_define (pfile, "__cpp_structured_bindings=201606");
+ cpp_define (pfile, "__cpp_variadic_using=201611");
}
if (flag_concepts)
- /* Use a value smaller than the 201507 specified in
- the TS, since we don't yet support extended auto. */
- cpp_define (pfile, "__cpp_concepts=201500");
+ cpp_define (pfile, "__cpp_concepts=201507");
if (flag_tm)
/* Use a value smaller than the 201505 specified in
the TS, since we don't yet support atomic_cancel. */
cpp_define (pfile, "__cpp_transactional_memory=210500");
if (flag_sized_deallocation)
cpp_define (pfile, "__cpp_sized_deallocation=201309");
+ if (aligned_new_threshold)
+ {
+ cpp_define (pfile, "__cpp_aligned_new=201606");
+ cpp_define_formatted (pfile, "__STDCPP_DEFAULT_NEW_ALIGNMENT__=%d",
+ aligned_new_threshold);
+ }
+ if (flag_new_ttp)
+ cpp_define (pfile, "__cpp_template_template_args=201611");
}
/* Note that we define this for C as well, so that we know if
__attribute__((cleanup)) will interface with EH. */
@@ -931,6 +1027,24 @@ c_cpp_builtins (cpp_reader *pfile)
builtin_define_type_max ("__PTRDIFF_MAX__", ptrdiff_type_node);
builtin_define_type_max ("__SIZE_MAX__", size_type_node);
+ /* These are needed for TS 18661-1. */
+ builtin_define_type_width ("__SCHAR_WIDTH__", signed_char_type_node,
+ unsigned_char_type_node);
+ builtin_define_type_width ("__SHRT_WIDTH__", short_integer_type_node,
+ short_unsigned_type_node);
+ builtin_define_type_width ("__INT_WIDTH__", integer_type_node,
+ unsigned_type_node);
+ builtin_define_type_width ("__LONG_WIDTH__", long_integer_type_node,
+ long_unsigned_type_node);
+ builtin_define_type_width ("__LONG_LONG_WIDTH__",
+ long_long_integer_type_node,
+ long_long_unsigned_type_node);
+ builtin_define_type_width ("__WCHAR_WIDTH__", underlying_wchar_type_node,
+ NULL_TREE);
+ builtin_define_type_width ("__WINT_WIDTH__", wint_type_node, NULL_TREE);
+ builtin_define_type_width ("__PTRDIFF_WIDTH__", ptrdiff_type_node, NULL_TREE);
+ builtin_define_type_width ("__SIZE_WIDTH__", size_type_node, NULL_TREE);
+
if (c_dialect_cxx ())
for (i = 0; i < NUM_INT_N_ENTS; i ++)
if (int_n_enabled_p[i])
@@ -959,9 +1073,22 @@ c_cpp_builtins (cpp_reader *pfile)
builtin_define_with_int_value ("__GCC_IEC_559_COMPLEX",
cpp_iec_559_complex_value ());
- /* float.h needs to know this. */
+ /* float.h needs these to correctly set FLT_EVAL_METHOD
+
+ We define two values:
+
+ __FLT_EVAL_METHOD__
+ Which, depending on the value given for
+ -fpermitted-flt-eval-methods, may be limited to only those values
+ for FLT_EVAL_METHOD defined in C99/C11.
+
+ __FLT_EVAL_METHOD_TS_18661_3__
+ Which always permits the values for FLT_EVAL_METHOD defined in
+ ISO/IEC TS 18661-3. */
builtin_define_with_int_value ("__FLT_EVAL_METHOD__",
- TARGET_FLT_EVAL_METHOD);
+ c_flt_eval_method (true));
+ builtin_define_with_int_value ("__FLT_EVAL_METHOD_TS_18661_3__",
+ c_flt_eval_method (false));
/* And decfloat.h needs this. */
builtin_define_with_int_value ("__DEC_EVAL_METHOD__",
@@ -981,6 +1108,19 @@ c_cpp_builtins (cpp_reader *pfile)
builtin_define_float_constants ("LDBL", "L", "%s", "L",
long_double_type_node);
+ for (int i = 0; i < NUM_FLOATN_NX_TYPES; i++)
+ {
+ if (FLOATN_NX_TYPE_NODE (i) == NULL_TREE)
+ continue;
+ char prefix[20], csuffix[20];
+ sprintf (prefix, "FLT%d%s", floatn_nx_types[i].n,
+ floatn_nx_types[i].extended ? "X" : "");
+ sprintf (csuffix, "F%d%s", floatn_nx_types[i].n,
+ floatn_nx_types[i].extended ? "x" : "");
+ builtin_define_float_constants (prefix, csuffix, "%s", NULL,
+ FLOATN_NX_TYPE_NODE (i));
+ }
+
/* For decfloat.h. */
builtin_define_decimal_float_constants ("DEC32", "DF", dfloat32_type_node);
builtin_define_decimal_float_constants ("DEC64", "DD", dfloat64_type_node);
@@ -1067,44 +1207,60 @@ c_cpp_builtins (cpp_reader *pfile)
macro_name = (char *) alloca (strlen (name)
+ sizeof ("__LIBGCC__FUNC_EXT__"));
sprintf (macro_name, "__LIBGCC_%s_FUNC_EXT__", name);
- const char *suffix;
+ char suffix[20] = "";
if (mode == TYPE_MODE (double_type_node))
- suffix = "";
+ ; /* Empty suffix correct. */
else if (mode == TYPE_MODE (float_type_node))
- suffix = "f";
+ suffix[0] = 'f';
else if (mode == TYPE_MODE (long_double_type_node))
- suffix = "l";
- /* ??? The following assumes the built-in functions (defined
- in target-specific code) match the suffixes used for
- constants. Because in fact such functions are not
- defined for the 'w' suffix, 'l' is used there
- instead. */
- else if (mode == targetm.c.mode_for_suffix ('q'))
- suffix = "q";
- else if (mode == targetm.c.mode_for_suffix ('w'))
- suffix = "l";
+ suffix[0] = 'l';
else
- gcc_unreachable ();
+ {
+ bool found_suffix = false;
+ for (int i = 0; i < NUM_FLOATN_NX_TYPES; i++)
+ if (FLOATN_NX_TYPE_NODE (i) != NULL_TREE
+ && mode == TYPE_MODE (FLOATN_NX_TYPE_NODE (i)))
+ {
+ sprintf (suffix, "f%d%s", floatn_nx_types[i].n,
+ floatn_nx_types[i].extended ? "x" : "");
+ found_suffix = true;
+ break;
+ }
+ gcc_assert (found_suffix);
+ }
builtin_define_with_value (macro_name, suffix, 0);
+
+ /* The way __LIBGCC_*_EXCESS_PRECISION__ is used is about
+ eliminating excess precision from results assigned to
+ variables - meaning it should be about the implicit excess
+ precision only. */
bool excess_precision = false;
- if (TARGET_FLT_EVAL_METHOD != 0
- && mode != TYPE_MODE (long_double_type_node)
- && (mode == TYPE_MODE (float_type_node)
- || mode == TYPE_MODE (double_type_node)))
- switch (TARGET_FLT_EVAL_METHOD)
- {
- case -1:
- case 2:
- excess_precision = true;
- break;
-
- case 1:
- excess_precision = mode == TYPE_MODE (float_type_node);
- break;
-
- default:
- gcc_unreachable ();
- }
+ machine_mode float16_type_mode = (float16_type_node
+ ? TYPE_MODE (float16_type_node)
+ : VOIDmode);
+ switch (targetm.c.excess_precision
+ (EXCESS_PRECISION_TYPE_IMPLICIT))
+ {
+ case FLT_EVAL_METHOD_UNPREDICTABLE:
+ case FLT_EVAL_METHOD_PROMOTE_TO_LONG_DOUBLE:
+ excess_precision = (mode == float16_type_mode
+ || mode == TYPE_MODE (float_type_node)
+ || mode == TYPE_MODE (double_type_node));
+ break;
+
+ case FLT_EVAL_METHOD_PROMOTE_TO_DOUBLE:
+ excess_precision = (mode == float16_type_mode
+ || mode == TYPE_MODE (float_type_node));
+ break;
+ case FLT_EVAL_METHOD_PROMOTE_TO_FLOAT:
+ excess_precision = mode == float16_type_mode;
+ break;
+ case FLT_EVAL_METHOD_PROMOTE_TO_FLOAT16:
+ excess_precision = false;
+ break;
+ default:
+ gcc_unreachable ();
+ }
macro_name = (char *) alloca (strlen (name)
+ sizeof ("__LIBGCC__EXCESS_"
"PRECISION__"));
@@ -1119,10 +1275,6 @@ c_cpp_builtins (cpp_reader *pfile)
builtin_define_with_value ("__LIBGCC_EH_FRAME_SECTION_NAME__",
EH_FRAME_SECTION_NAME, 1);
#endif
-#ifdef JCR_SECTION_NAME
- builtin_define_with_value ("__LIBGCC_JCR_SECTION_NAME__",
- JCR_SECTION_NAME, 1);
-#endif
#ifdef CTORS_SECTION_ASM_OP
builtin_define_with_value ("__LIBGCC_CTORS_SECTION_ASM_OP__",
CTORS_SECTION_ASM_OP, 1);
@@ -1662,4 +1814,15 @@ builtin_define_type_minmax (const char *min_macro, const char *max_macro,
}
}
+/* Define WIDTH_MACRO for the width of TYPE. If TYPE2 is not NULL,
+ both types must have the same width. */
+
+static void
+builtin_define_type_width (const char *width_macro, tree type, tree type2)
+{
+ if (type2 != NULL_TREE)
+ gcc_assert (TYPE_PRECISION (type) == TYPE_PRECISION (type2));
+ builtin_define_with_int_value (width_macro, TYPE_PRECISION (type));
+}
+
#include "gt-c-family-c-cppbuiltin.h"
diff --git a/gcc/c-family/c-dump.c b/gcc/c-family/c-dump.c
index da6b99da81..67ad98a31e 100644
--- a/gcc/c-family/c-dump.c
+++ b/gcc/c-family/c-dump.c
@@ -1,5 +1,5 @@
/* Tree-dumping functionality for C-family languages.
- Copyright (C) 2002-2016 Free Software Foundation, Inc.
+ Copyright (C) 2002-2017 Free Software Foundation, Inc.
Written by Mark Mitchell <mark@codesourcery.com>
This file is part of GCC.
diff --git a/gcc/c-family/c-format.c b/gcc/c-family/c-format.c
index c19c411d61..400eb666d5 100644
--- a/gcc/c-family/c-format.c
+++ b/gcc/c-family/c-format.c
@@ -1,5 +1,5 @@
/* Check calls to formatted I/O functions (-Wformat).
- Copyright (C) 1992-2016 Free Software Foundation, Inc.
+ Copyright (C) 1992-2017 Free Software Foundation, Inc.
This file is part of GCC.
@@ -29,6 +29,10 @@ along with GCC; see the file COPYING3. If not see
#include "intl.h"
#include "langhooks.h"
#include "c-format.h"
+#include "diagnostic.h"
+#include "substring-locations.h"
+#include "selftest.h"
+#include "builtins.h"
/* Handle attributes associated with format checking. */
@@ -65,78 +69,33 @@ static int first_target_format_type;
static const char *format_name (int format_num);
static int format_flags (int format_num);
-/* Given a string S of length LINE_WIDTH, find the visual column
- corresponding to OFFSET bytes. */
+/* Emit a warning as per format_warning_va, but construct the substring_loc
+ for the character at offset (CHAR_IDX - 1) within a string constant
+ FORMAT_STRING_CST at FMT_STRING_LOC. */
-static unsigned int
-location_column_from_byte_offset (const char *s, int line_width,
- unsigned int offset)
-{
- const char * c = s;
- if (*c != '"')
- return 0;
-
- c++, offset--;
- while (offset > 0)
- {
- if (c - s >= line_width)
- return 0;
-
- switch (*c)
- {
- case '\\':
- c++;
- if (c - s >= line_width)
- return 0;
- switch (*c)
- {
- case '\\': case '\'': case '"': case '?':
- case '(': case '{': case '[': case '%':
- case 'a': case 'b': case 'f': case 'n':
- case 'r': case 't': case 'v':
- case 'e': case 'E':
- c++, offset--;
- break;
-
- default:
- return 0;
- }
- break;
-
- case '"':
- /* We found the end of the string too early. */
- return 0;
-
- default:
- c++, offset--;
- break;
- }
- }
- return c - s;
-}
-
-/* Return a location that encodes the same location as LOC but shifted
- by OFFSET bytes. */
-
-static location_t
-location_from_offset (location_t loc, int offset)
+ATTRIBUTE_GCC_DIAG (5,6)
+static bool
+format_warning_at_char (location_t fmt_string_loc, tree format_string_cst,
+ int char_idx, int opt, const char *gmsgid, ...)
{
- gcc_checking_assert (offset >= 0);
- if (linemap_location_from_macro_expansion_p (line_table, loc)
- || offset < 0)
- return loc;
-
- expanded_location s = expand_location_to_spelling_point (loc);
- int line_width;
- const char *line = location_get_source_line (s.file, s.line, &line_width);
- if (line == NULL)
- return loc;
- line += s.column - 1 ;
- line_width -= s.column - 1;
- unsigned int column =
- location_column_from_byte_offset (line, line_width, (unsigned) offset);
-
- return linemap_position_for_loc_and_offset (line_table, loc, column);
+ va_list ap;
+ va_start (ap, gmsgid);
+ tree string_type = TREE_TYPE (format_string_cst);
+
+ /* The callers are of the form:
+ format_warning (format_string_loc, format_string_cst,
+ format_chars - orig_format_chars,
+ where format_chars has already been incremented, so that
+ CHAR_IDX is one character beyond where the warning should
+ be emitted. Fix it. */
+ char_idx -= 1;
+
+ substring_loc fmt_loc (fmt_string_loc, string_type, char_idx, char_idx,
+ char_idx);
+ bool warned = format_warning_va (fmt_loc, NULL, NULL, opt, gmsgid, &ap);
+ va_end (ap);
+
+ return warned;
}
/* Check that we have a pointer to a string suitable for use as a format.
@@ -248,7 +207,7 @@ check_format_string (tree fntype, unsigned HOST_WIDE_INT format_num,
{
/* We expected a char but found an extended string type. */
if (is_objc_sref)
- error ("found a %<%s%> reference but the format argument should"
+ error ("found a %qs 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",
@@ -261,7 +220,7 @@ check_format_string (tree fntype, unsigned HOST_WIDE_INT format_num,
/* We expect a string object type as the format arg. */
if (is_char_ref)
{
- error ("format argument should be a %<%s%> reference but"
+ error ("format argument should be a %qs reference but"
" a string was found", format_name (expected_format_type));
*no_add_attrs = true;
return false;
@@ -283,7 +242,7 @@ check_format_string (tree fntype, unsigned HOST_WIDE_INT format_num,
return true;
else
{
- error ("format argument should be a %<%s%> reference",
+ error ("format argument should be a %qs reference",
format_name (expected_format_type));
*no_add_attrs = true;
return false;
@@ -754,6 +713,7 @@ static const format_char_info gcc_tdiag_char_table[] =
{ "r", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "cR", NULL },
{ "<>'R",0, STD_C89, NOARGUMENTS, "", "", NULL },
{ "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL },
+ { "Z", 1, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "", &gcc_tdiag_char_table[0] },
{ NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
};
@@ -777,6 +737,7 @@ static const format_char_info gcc_cdiag_char_table[] =
{ "r", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "cR", NULL },
{ "<>'R",0, STD_C89, NOARGUMENTS, "", "", NULL },
{ "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL },
+ { "Z", 1, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "", &gcc_tdiag_char_table[0] },
{ NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
};
@@ -803,6 +764,7 @@ static const format_char_info gcc_cxxdiag_char_table[] =
{ "r", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "cR", NULL },
{ "<>'R",0, STD_C89, NOARGUMENTS, "", "", NULL },
{ "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL },
+ { "Z", 1, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "", &gcc_tdiag_char_table[0] },
{ NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
};
@@ -1018,8 +980,9 @@ format_flags (int format_num)
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,
+ function_format_info *, const char *,
+ location_t, tree,
+ int, tree,
unsigned HOST_WIDE_INT,
object_allocator<format_wanted_type> &);
@@ -1032,8 +995,18 @@ 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 (location_t, format_wanted_type *);
-static void format_type_warning (location_t, format_wanted_type *, tree, tree);
+static void check_format_types (const substring_loc &fmt_loc,
+ format_wanted_type *,
+ const format_kind_info *fki,
+ int offset_to_type_start,
+ char conversion_char);
+static void format_type_warning (const substring_loc &fmt_loc,
+ source_range *param_range,
+ format_wanted_type *, tree,
+ tree,
+ const format_kind_info *fki,
+ int offset_to_type_start,
+ char conversion_char);
/* 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
@@ -1092,9 +1065,17 @@ check_function_format (tree attrs, int nargs, tree *argarray)
params = tree_cons (NULL_TREE, argarray[i], params);
check_format_info (&info, params);
}
+
+ /* Attempt to detect whether the current function might benefit
+ from the format attribute if the called function is decorated
+ with it. Avoid using calls with string literal formats for
+ guidance since those are unlikely to be viable candidates. */
if (warn_suggest_attribute_format && info.first_arg_num == 0
&& (format_types[info.format_type].flags
- & (int) FMT_FLAG_ARG_CONVERT))
+ & (int) FMT_FLAG_ARG_CONVERT)
+ /* c_strlen will fail for a function parameter but succeed
+ for a literal or constant array. */
+ && !c_strlen (argarray[info.format_num - 1], 1))
{
tree c;
for (c = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
@@ -1122,8 +1103,9 @@ check_function_format (tree attrs, int nargs, tree *argarray)
break;
}
if (args != 0)
- warning (OPT_Wsuggest_attribute_format, "function might "
- "be possible candidate for %qs format attribute",
+ warning (OPT_Wsuggest_attribute_format, "function %qD "
+ "might be a candidate for %qs format attribute",
+ current_function_decl,
format_types[info.format_type].name);
}
}
@@ -1509,6 +1491,8 @@ check_format_arg (void *ctx, tree format_tree,
tree array_size = 0;
tree array_init;
+ location_t fmt_param_loc = EXPR_LOC_OR_LOC (format_tree, input_location);
+
if (VAR_P (format_tree))
{
/* Pull out a constant value if the front end didn't. */
@@ -1684,751 +1668,1164 @@ check_format_arg (void *ctx, tree format_tree,
need not adjust it for every return. */
res->number_other++;
object_allocator <format_wanted_type> fwt_pool ("format_wanted_type pool");
- check_format_info_main (res, info, format_chars, format_length,
- params, arg_num, fwt_pool);
+ check_format_info_main (res, info, format_chars, fmt_param_loc, format_tree,
+ format_length, params, arg_num, fwt_pool);
}
+/* Support class for argument_parser and check_format_info_main.
+ Tracks any flag characters that have been applied to the
+ current argument. */
-/* 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. */
+class flag_chars_t
+{
+ public:
+ flag_chars_t ();
+ bool has_char_p (char ch) const;
+ void add_char (char ch);
+ void validate (const format_kind_info *fki,
+ const format_char_info *fci,
+ const format_flag_spec *flag_specs,
+ const char * const format_chars,
+ tree format_string_cst,
+ location_t format_string_loc,
+ const char * const orig_format_chars,
+ char format_char);
+ int get_alloc_flag (const format_kind_info *fki);
+ int assignment_suppression_p (const format_kind_info *fki);
+
+ private:
+ char m_flag_chars[256];
+};
-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,
- object_allocator <format_wanted_type> &fwt_pool)
+/* Support struct for argument_parser and check_format_info_main.
+ Encapsulates any length modifier applied to the current argument. */
+
+struct length_modifier
{
- const char *orig_format_chars = format_chars;
- tree first_fillin_param = params;
+ length_modifier ()
+ : chars (NULL), val (FMT_LEN_none), std (STD_C89),
+ scalar_identity_flag (0)
+ {
+ }
- 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;
- location_t format_string_loc = res->format_string_loc;
+ length_modifier (const char *chars_,
+ enum format_lengths val_,
+ enum format_std_version std_,
+ int scalar_identity_flag_)
+ : chars (chars_), val (val_), std (std_),
+ scalar_identity_flag (scalar_identity_flag_)
+ {
+ }
- /* -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;
+ const char *chars;
+ enum format_lengths val;
+ enum format_std_version std;
+ int scalar_identity_flag;
+};
- init_dollar_format_checking (info->first_arg_num, first_fillin_param);
+/* Parsing one argument within a format string. */
- 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;
+class argument_parser
+{
+ public:
+ argument_parser (function_format_info *info, const char *&format_chars,
+ tree format_string_cst,
+ const char * const orig_format_chars,
+ location_t format_string_loc, flag_chars_t &flag_chars,
+ int &has_operand_number, tree first_fillin_param,
+ object_allocator <format_wanted_type> &fwt_pool_);
+
+ bool read_any_dollar ();
+
+ bool read_format_flags ();
+
+ bool
+ read_any_format_width (tree &params,
+ unsigned HOST_WIDE_INT &arg_num);
+
+ void
+ read_any_format_left_precision ();
+
+ bool
+ read_any_format_precision (tree &params,
+ unsigned HOST_WIDE_INT &arg_num);
+
+ void handle_alloc_chars ();
+
+ length_modifier read_any_length_modifier ();
+
+ void read_any_other_modifier ();
+
+ const format_char_info *find_format_char_info (char format_char);
+
+ void
+ validate_flag_pairs (const format_char_info *fci,
+ char format_char);
+
+ void
+ give_y2k_warnings (const format_char_info *fci,
+ char format_char);
+
+ void parse_any_scan_set (const format_char_info *fci);
+
+ bool handle_conversions (const format_char_info *fci,
+ const length_modifier &len_modifier,
+ tree &wanted_type,
+ const char *&wanted_type_name,
+ unsigned HOST_WIDE_INT &arg_num,
+ tree &params,
+ char format_char);
+
+ bool
+ check_argument_type (const format_char_info *fci,
+ const length_modifier &len_modifier,
+ tree &wanted_type,
+ const char *&wanted_type_name,
+ const bool suppressed,
+ unsigned HOST_WIDE_INT &arg_num,
+ tree &params,
+ const int alloc_flag,
+ const char * const format_start,
+ const char * const type_start,
+ location_t fmt_param_loc,
+ char conversion_char);
+
+ private:
+ const function_format_info *const info;
+ const format_kind_info * const fki;
+ const format_flag_spec * const flag_specs;
+ const char *start_of_this_format;
+ const char *&format_chars;
+ const tree format_string_cst;
+ const char * const orig_format_chars;
+ const location_t format_string_loc;
+ object_allocator <format_wanted_type> &fwt_pool;
+ flag_chars_t &flag_chars;
+ int main_arg_num;
+ tree main_arg_params;
+ int &has_operand_number;
+ const tree first_fillin_param;
+ format_wanted_type width_wanted_type;
+ format_wanted_type precision_wanted_type;
+ public:
+ format_wanted_type main_wanted_type;
+ private:
+ format_wanted_type *first_wanted_type;
+ format_wanted_type *last_wanted_type;
+};
- if (*format_chars++ != '%')
+/* flag_chars_t's constructor. */
+
+flag_chars_t::flag_chars_t ()
+{
+ m_flag_chars[0] = 0;
+}
+
+/* Has CH been seen as a flag within the current argument? */
+
+bool
+flag_chars_t::has_char_p (char ch) const
+{
+ return strchr (m_flag_chars, ch) != 0;
+}
+
+/* Add CH to the flags seen within the current argument. */
+
+void
+flag_chars_t::add_char (char ch)
+{
+ int i = strlen (m_flag_chars);
+ m_flag_chars[i++] = ch;
+ m_flag_chars[i] = 0;
+}
+
+/* Validate the individual flags used, removing any that are invalid. */
+
+void
+flag_chars_t::validate (const format_kind_info *fki,
+ const format_char_info *fci,
+ const format_flag_spec *flag_specs,
+ const char * const format_chars,
+ tree format_string_cst,
+ location_t format_string_loc,
+ const char * const orig_format_chars,
+ char format_char)
+{
+ int i;
+ int d = 0;
+ for (i = 0; m_flag_chars[i] != 0; i++)
+ {
+ const format_flag_spec *s = get_flag_spec (flag_specs,
+ m_flag_chars[i], NULL);
+ m_flag_chars[i - d] = m_flag_chars[i];
+ if (m_flag_chars[i] == fki->length_code_char)
continue;
- if (*format_chars == 0)
+ if (strchr (fci->flag_chars, m_flag_chars[i]) == 0)
{
- warning_at (location_from_offset (format_string_loc,
- format_chars - orig_format_chars),
- OPT_Wformat_,
- "spurious trailing %<%%%> in format");
+ format_warning_at_char (format_string_loc, format_string_cst,
+ format_chars - orig_format_chars,
+ OPT_Wformat_,
+ "%s used with %<%%%c%> %s format",
+ _(s->name), format_char, fki->name);
+ d++;
continue;
}
- if (*format_chars == '%')
+ if (pedantic)
+ {
+ const format_flag_spec *t;
+ if (ADJ_STD (s->std) > C_STD_VER)
+ warning_at (format_string_loc, OPT_Wformat_,
+ "%s does not support %s",
+ C_STD_NAME (s->std), _(s->long_name));
+ t = get_flag_spec (flag_specs, m_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_at (format_string_loc, OPT_Wformat_,
+ "%s does not support %s with"
+ " the %<%%%c%> %s format",
+ C_STD_NAME (t->std), _(long_name),
+ format_char, fki->name);
+ }
+ }
+ }
+ m_flag_chars[i - d] = 0;
+}
+
+/* Determine if an assignment-allocation has been set, requiring
+ an extra char ** for writing back a dynamically-allocated char *.
+ This is for handling the optional 'm' character in scanf. */
+
+int
+flag_chars_t::get_alloc_flag (const format_kind_info *fki)
+{
+ if ((fki->flags & (int) FMT_FLAG_SCANF_A_KLUDGE)
+ && has_char_p ('a'))
+ return 1;
+ if (fki->alloc_char && has_char_p (fki->alloc_char))
+ return 1;
+ return 0;
+}
+
+/* Determine if an assignment-suppression character was seen.
+ ('*' in scanf, for discarding the converted input). */
+
+int
+flag_chars_t::assignment_suppression_p (const format_kind_info *fki)
+{
+ if (fki->suppression_char
+ && has_char_p (fki->suppression_char))
+ return 1;
+ return 0;
+}
+
+/* Constructor for argument_parser. Initialize for parsing one
+ argument within a format string. */
+
+argument_parser::
+argument_parser (function_format_info *info_, const char *&format_chars_,
+ tree format_string_cst_,
+ const char * const orig_format_chars_,
+ location_t format_string_loc_,
+ flag_chars_t &flag_chars_,
+ int &has_operand_number_,
+ tree first_fillin_param_,
+ object_allocator <format_wanted_type> &fwt_pool_)
+: info (info_),
+ fki (&format_types[info->format_type]),
+ flag_specs (fki->flag_specs),
+ start_of_this_format (format_chars_),
+ format_chars (format_chars_),
+ format_string_cst (format_string_cst_),
+ orig_format_chars (orig_format_chars_),
+ format_string_loc (format_string_loc_),
+ fwt_pool (fwt_pool_),
+ flag_chars (flag_chars_),
+ main_arg_num (0),
+ main_arg_params (NULL),
+ has_operand_number (has_operand_number_),
+ first_fillin_param (first_fillin_param_),
+ first_wanted_type (NULL),
+ last_wanted_type (NULL)
+{
+}
+
+/* Handle dollars at the start of format arguments, setting up main_arg_params
+ and main_arg_num.
+
+ Return true if format parsing is to continue, false otherwise. */
+
+bool
+argument_parser::read_any_dollar ()
+{
+ 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 false;
+ 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 false;
+ }
+ return true;
+}
+
+/* Read any format flags, but do not yet validate them beyond removing
+ duplicates, since in general validation depends on the rest of
+ the format.
+
+ Return true if format parsing is to continue, false otherwise. */
+
+bool
+argument_parser::read_format_flags ()
+{
+ 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 (flag_chars.has_char_p (*format_chars))
+ {
+ format_warning_at_char (format_string_loc, format_string_cst,
+ format_chars + 1 - orig_format_chars,
+ OPT_Wformat_,
+ "repeated %s in format", _(s->name));
+ }
+ else
+ flag_chars.add_char (*format_chars);
+
+ if (s->skip_next_char)
{
++format_chars;
- continue;
+ if (*format_chars == 0)
+ {
+ warning_at (format_string_loc, OPT_Wformat_,
+ "missing fill character at end of strfmon format");
+ return false;
+ }
}
- flag_chars[0] = 0;
+ ++format_chars;
+ }
+
+ return true;
+}
+
+/* Read any format width, possibly * or *m$.
- if ((fki->flags & (int) FMT_FLAG_USE_DOLLAR) && has_operand_number != 0)
+ Return true if format parsing is to continue, false otherwise. */
+
+bool
+argument_parser::
+read_any_format_width (tree &params,
+ unsigned HOST_WIDE_INT &arg_num)
+{
+ if (!fki->width_char)
+ return true;
+
+ if (fki->width_type != NULL && *format_chars == '*')
+ {
+ flag_chars.add_char (fki->width_char);
+ /* "...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)
{
- /* 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,
+ opnum = maybe_read_dollar_number (&format_chars,
+ has_operand_number == 1,
first_fillin_param,
- &main_arg_params, fki);
+ &params, fki);
if (opnum == -1)
- return;
+ return false;
else if (opnum > 0)
{
has_operand_number = 1;
- main_arg_num = opnum + info->first_arg_num - 1;
+ arg_num = opnum + info->first_arg_num - 1;
}
+ else
+ has_operand_number = 0;
}
- else if (fki->flags & FMT_FLAG_USE_DOLLAR)
+ else
{
if (avoid_dollar_number (format_chars))
- return;
+ return false;
}
-
- /* 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)
+ if (info->first_arg_num != 0)
{
- const format_flag_spec *s = get_flag_spec (flag_specs,
- *format_chars, NULL);
- if (strchr (flag_chars, *format_chars) != 0)
- {
- warning_at (location_from_offset (format_string_loc,
- format_chars + 1
- - orig_format_chars),
- OPT_Wformat_,
- "repeated %s in format", _(s->name));
- }
+ tree cur_param;
+ if (params == 0)
+ cur_param = NULL;
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)
+ cur_param = TREE_VALUE (params);
+ if (has_operand_number <= 0)
{
- warning_at (format_string_loc, OPT_Wformat_,
- "missing fill character at end of strfmon format");
- return;
+ 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.offset_loc =
+ format_chars - orig_format_chars;
+ 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_at (format_string_loc, OPT_Wformat_,
+ "zero width in %s format", fki->name);
+ if (found_width)
+ flag_chars.add_char (fki->width_char);
+ }
- /* Read any format width, possibly * or *m$. */
- if (fki->width_char != 0)
+ return true;
+}
+
+/* Read any format left precision (must be a number, not *). */
+void
+argument_parser::read_any_format_left_precision ()
+{
+ if (fki->left_precision_char == 0)
+ return;
+ if (*format_chars != '#')
+ return;
+
+ ++format_chars;
+ flag_chars.add_char (fki->left_precision_char);
+ if (!ISDIGIT (*format_chars))
+ format_warning_at_char (format_string_loc, format_string_cst,
+ format_chars - orig_format_chars,
+ OPT_Wformat_,
+ "empty left precision in %s format", fki->name);
+ while (ISDIGIT (*format_chars))
+ ++format_chars;
+}
+
+/* Read any format precision, possibly * or *m$.
+
+ Return true if format parsing is to continue, false otherwise. */
+
+bool
+argument_parser::
+read_any_format_precision (tree &params,
+ unsigned HOST_WIDE_INT &arg_num)
+{
+ if (fki->precision_char == 0)
+ return true;
+ if (*format_chars != '.')
+ return true;
+
+ ++format_chars;
+ flag_chars.add_char (fki->precision_char);
+ 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)
{
- if (fki->width_type != NULL && *format_chars == '*')
+ int opnum;
+ opnum = maybe_read_dollar_number (&format_chars,
+ has_operand_number == 1,
+ first_fillin_param,
+ &params, fki);
+ if (opnum == -1)
+ return false;
+ else if (opnum > 0)
{
- i = strlen (flag_chars);
- flag_chars[i++] = fki->width_char;
- flag_chars[i] = 0;
- /* "...a field width...may be indicated by an asterisk.
- In this case, an int argument supplies the field width..." */
- ++format_chars;
- if (has_operand_number != 0)
- {
- int opnum;
- opnum = maybe_read_dollar_number (&format_chars,
- has_operand_number == 1,
- first_fillin_param,
- &params, fki);
- if (opnum == -1)
- return;
- else if (opnum > 0)
- {
- has_operand_number = 1;
- arg_num = opnum + info->first_arg_num - 1;
- }
- else
- has_operand_number = 0;
- }
- else
- {
- if (avoid_dollar_number (format_chars))
- return;
- }
- if (info->first_arg_num != 0)
- {
- if (params == 0)
- cur_param = NULL;
- else
- {
- cur_param = TREE_VALUE (params);
- if (has_operand_number <= 0)
- {
- params = TREE_CHAIN (params);
- ++arg_num;
- }
- }
- width_wanted_type.wanted_type = *fki->width_type;
- width_wanted_type.wanted_type_name = NULL;
- width_wanted_type.pointer_count = 0;
- width_wanted_type.char_lenient_flag = 0;
- width_wanted_type.scalar_identity_flag = 0;
- width_wanted_type.writing_in_flag = 0;
- width_wanted_type.reading_from_flag = 0;
- width_wanted_type.kind = CF_KIND_FIELD_WIDTH;
- width_wanted_type.format_start = format_chars - 1;
- width_wanted_type.format_length = 1;
- width_wanted_type.param = cur_param;
- width_wanted_type.arg_num = arg_num;
- width_wanted_type.offset_loc =
- format_chars - orig_format_chars;
- 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;
- }
+ has_operand_number = 1;
+ arg_num = opnum + info->first_arg_num - 1;
}
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_at (format_string_loc, 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;
- }
- }
+ has_operand_number = 0;
}
-
- /* Read any format left precision (must be a number, not *). */
- if (fki->left_precision_char != 0 && *format_chars == '#')
+ else
{
- ++format_chars;
- i = strlen (flag_chars);
- flag_chars[i++] = fki->left_precision_char;
- flag_chars[i] = 0;
- if (!ISDIGIT (*format_chars))
- warning_at (location_from_offset (format_string_loc,
- format_chars - orig_format_chars),
- OPT_Wformat_,
- "empty left precision in %s format", fki->name);
- while (ISDIGIT (*format_chars))
- ++format_chars;
+ if (avoid_dollar_number (format_chars))
+ return false;
}
-
- /* Read any format precision, possibly * or *m$. */
- if (fki->precision_char != 0 && *format_chars == '.')
+ if (info->first_arg_num != 0)
{
- ++format_chars;
- i = strlen (flag_chars);
- flag_chars[i++] = fki->precision_char;
- flag_chars[i] = 0;
- if (fki->precision_type != NULL && *format_chars == '*')
+ tree cur_param;
+ if (params == 0)
+ cur_param = NULL;
+ else
{
- /* "...a...precision...may be indicated by an asterisk.
- In this case, an int argument supplies the...precision." */
- ++format_chars;
- if (has_operand_number != 0)
+ cur_param = TREE_VALUE (params);
+ if (has_operand_number <= 0)
{
- int opnum;
- opnum = maybe_read_dollar_number (&format_chars,
- has_operand_number == 1,
- first_fillin_param,
- &params, fki);
- if (opnum == -1)
- return;
- else if (opnum > 0)
- {
- has_operand_number = 1;
- arg_num = opnum + info->first_arg_num - 1;
- }
- else
- has_operand_number = 0;
+ params = TREE_CHAIN (params);
+ ++arg_num;
}
- 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.offset_loc =
- format_chars - orig_format_chars;
- 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_at (location_from_offset (format_string_loc,
- format_chars - orig_format_chars),
- OPT_Wformat_,
- "empty precision in %s format", fki->name);
- while (ISDIGIT (*format_chars))
- ++format_chars;
}
+ 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.offset_loc =
+ format_chars - orig_format_chars;
+ 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))
+ format_warning_at_char (format_string_loc, format_string_cst,
+ format_chars - orig_format_chars,
+ 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++;
- }
+ return true;
+}
- /* Handle the scanf allocation kludge. */
- if (fki->flags & (int) FMT_FLAG_SCANF_A_KLUDGE)
+/* Parse any assignment-allocation flags, which request an extra
+ char ** for writing back a dynamically-allocated char *.
+ This is for handling the optional 'm' character in scanf,
+ and, before C99, 'a' (for compatibility with a non-standard
+ GNU libc extension). */
+
+void
+argument_parser::handle_alloc_chars ()
+{
+ if (fki->alloc_char && fki->alloc_char == *format_chars)
+ {
+ flag_chars.add_char (fki->alloc_char);
+ 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 == 'a' && !flag_isoc99)
+ if (format_chars[1] == 's' || format_chars[1] == 'S'
+ || format_chars[1] == '[')
{
- 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++;
- }
+ /* 'a' is used as a flag. */
+ flag_chars.add_char ('a');
+ 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)
+/* Look for length modifiers within the current format argument,
+ returning a length_modifier instance describing it (or the
+ default if one is not found).
+
+ Issue warnings about non-standard modifiers. */
+
+length_modifier
+argument_parser::read_any_length_modifier ()
+{
+ length_modifier result;
+
+ const format_length_info *fli = fki->length_char_specs;
+ if (!fli)
+ return result;
+
+ 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)
{
- 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_at (format_string_loc, OPT_Wformat_,
- "%s does not support the %qs %s length modifier",
- C_STD_NAME (length_chars_std), length_chars,
- fki->name);
- }
+ format_chars++;
+ result = length_modifier (fli->double_name, fli->double_index,
+ fli->double_std, 0);
}
-
- /* Read any modifier (strftime E/O). */
- if (fki->modifier_chars != NULL)
+ else
{
- 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_at (location_from_offset (format_string_loc,
- format_chars
- - orig_format_chars),
- OPT_Wformat_,
- "repeated %s in format", _(s->name));
- }
- else
- {
- i = strlen (flag_chars);
- flag_chars[i++] = *format_chars;
- flag_chars[i] = 0;
- }
- ++format_chars;
- }
+ result = length_modifier (fli->name, fli->index, fli->std,
+ fli->scalar_identity_flag);
}
+ flag_chars.add_char (fki->length_code_char);
+ }
+ if (pedantic)
+ {
+ /* Warn if the length modifier is non-standard. */
+ if (ADJ_STD (result.std) > C_STD_VER)
+ warning_at (format_string_loc, OPT_Wformat_,
+ "%s does not support the %qs %s length modifier",
+ C_STD_NAME (result.std), result.chars,
+ fki->name);
+ }
- format_char = *format_chars;
- if (format_char == 0
- || (!(fki->flags & (int) FMT_FLAG_FANCY_PERCENT_OK)
- && format_char == '%'))
+ return result;
+}
+
+/* Read any other modifier (strftime E/O). */
+
+void
+argument_parser::read_any_other_modifier ()
+{
+ if (fki->modifier_chars == NULL)
+ return;
+
+ while (*format_chars != 0
+ && strchr (fki->modifier_chars, *format_chars) != 0)
+ {
+ if (flag_chars.has_char_p (*format_chars))
{
- warning_at (location_from_offset (format_string_loc,
- format_chars - orig_format_chars),
- OPT_Wformat_,
- "conversion lacks type at end of format");
- continue;
+ const format_flag_spec *s = get_flag_spec (flag_specs,
+ *format_chars, NULL);
+ format_warning_at_char (format_string_loc, format_string_cst,
+ format_chars - orig_format_chars,
+ OPT_Wformat_,
+ "repeated %s in format", _(s->name));
}
- format_chars++;
- fci = fki->conversion_specs;
- while (fci->format_chars != 0
- && strchr (fci->format_chars, format_char) == 0)
- ++fci;
- if (fci->format_chars == 0)
+ else
+ flag_chars.add_char (*format_chars);
+ ++format_chars;
+ }
+}
+
+/* Return the format_char_info corresponding to FORMAT_CHAR,
+ potentially issuing a warning if the format char is
+ not supported in the C standard version we are checking
+ against.
+
+ Issue a warning and return NULL if it is not found.
+
+ Issue warnings about non-standard modifiers. */
+
+const format_char_info *
+argument_parser::find_format_char_info (char format_char)
+{
+ const format_char_info *fci = fki->conversion_specs;
+
+ while (fci->format_chars != 0
+ && strchr (fci->format_chars, format_char) == 0)
+ ++fci;
+ if (fci->format_chars == 0)
+ {
+ format_warning_at_char (format_string_loc, format_string_cst,
+ format_chars - orig_format_chars,
+ OPT_Wformat_,
+ "unknown conversion type character"
+ " %qc in format",
+ format_char);
+ return NULL;
+ }
+
+ if (pedantic)
+ {
+ if (ADJ_STD (fci->std) > C_STD_VER)
+ format_warning_at_char (format_string_loc, format_string_cst,
+ format_chars - orig_format_chars,
+ OPT_Wformat_,
+ "%s does not support the %<%%%c%> %s format",
+ C_STD_NAME (fci->std), format_char, fki->name);
+ }
+
+ return fci;
+}
+
+/* Validate the pairs of flags used.
+ Issue warnings about incompatible combinations of flags. */
+
+void
+argument_parser::validate_flag_pairs (const format_char_info *fci,
+ char format_char)
+{
+ const format_flag_pair * const bad_flag_pairs = fki->bad_flag_pairs;
+
+ for (int i = 0; bad_flag_pairs[i].flag_char1 != 0; i++)
+ {
+ const format_flag_spec *s, *t;
+ if (!flag_chars.has_char_p (bad_flag_pairs[i].flag_char1))
+ continue;
+ if (!flag_chars.has_char_p (bad_flag_pairs[i].flag_char2))
+ 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 (ISGRAPH (format_char))
- warning_at (location_from_offset (format_string_loc,
- format_chars - orig_format_chars),
- OPT_Wformat_,
- "unknown conversion type character %qc in format",
- format_char);
+ if (bad_flag_pairs[i].predicate != 0)
+ warning_at (format_string_loc, OPT_Wformat_,
+ "%s ignored with %s and %<%%%c%> %s format",
+ _(s->name), _(t->name), format_char,
+ fki->name);
else
- warning_at (location_from_offset (format_string_loc,
- format_chars - orig_format_chars),
- OPT_Wformat_,
- "unknown conversion type character 0x%x in format",
- format_char);
- continue;
+ warning_at (format_string_loc, OPT_Wformat_,
+ "%s ignored with %s in %s format",
+ _(s->name), _(t->name), fki->name);
}
- if (pedantic)
+ else
{
- if (ADJ_STD (fci->std) > C_STD_VER)
- warning_at (location_from_offset (format_string_loc,
- format_chars - orig_format_chars),
- OPT_Wformat_,
- "%s does not support the %<%%%c%> %s format",
- C_STD_NAME (fci->std), format_char, fki->name);
+ if (bad_flag_pairs[i].predicate != 0)
+ warning_at (format_string_loc, OPT_Wformat_,
+ "use of %s and %s together with %<%%%c%> %s format",
+ _(s->name), _(t->name), format_char,
+ fki->name);
+ else
+ warning_at (format_string_loc, OPT_Wformat_,
+ "use of %s and %s together in %s format",
+ _(s->name), _(t->name), 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_at (location_from_offset (format_string_loc,
- format_chars
- - orig_format_chars),
- 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_at (format_string_loc, 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_at (format_string_loc, 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;
+/* Give Y2K warnings. */
- /* Validate the pairs of flags used. */
- for (i = 0; bad_flag_pairs[i].flag_char1 != 0; i++)
+void
+argument_parser::give_y2k_warnings (const format_char_info *fci,
+ char format_char)
+{
+ if (!warn_format_y2k)
+ return;
+
+ int y2k_level = 0;
+ if (strchr (fci->flags2, '4') != 0)
+ if (flag_chars.has_char_p ('E'))
+ 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_at (format_string_loc, OPT_Wformat_y2k,
+ "%<%%%c%> yields only last 2 digits of "
+ "year in some locales", format_char);
+ else if (y2k_level == 2)
+ warning_at (format_string_loc, OPT_Wformat_y2k,
+ "%<%%%c%> yields only last 2 digits of year",
+ format_char);
+}
+
+/* Parse any "scan sets" enclosed in square brackets, e.g.
+ for scanf-style calls. */
+
+void
+argument_parser::parse_any_scan_set (const format_char_info *fci)
+{
+ if (strchr (fci->flags2, '[') == NULL)
+ return;
+
+ /* 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. */
+ format_warning_at_char (format_string_loc, format_string_cst,
+ format_chars - orig_format_chars,
+ OPT_Wformat_,
+ "no closing %<]%> for %<%%[%> format");
+}
+
+/* Return true if this argument is to be continued to be parsed,
+ false to skip to next argument. */
+
+bool
+argument_parser::handle_conversions (const format_char_info *fci,
+ const length_modifier &len_modifier,
+ tree &wanted_type,
+ const char *&wanted_type_name,
+ unsigned HOST_WIDE_INT &arg_num,
+ tree &params,
+ char format_char)
+{
+ enum format_std_version wanted_type_std;
+
+ if (!(fki->flags & (int) FMT_FLAG_ARG_CONVERT))
+ return true;
+
+ wanted_type = (fci->types[len_modifier.val].type
+ ? *fci->types[len_modifier.val].type : 0);
+ wanted_type_name = fci->types[len_modifier.val].name;
+ wanted_type_std = fci->types[len_modifier.val].std;
+ if (wanted_type == 0)
+ {
+ format_warning_at_char (format_string_loc, format_string_cst,
+ format_chars - orig_format_chars,
+ OPT_Wformat_,
+ "use of %qs length modifier with %qc type"
+ " character has either no effect"
+ " or undefined behavior",
+ len_modifier.chars, format_char);
+ /* Heuristic: skip one argument when an invalid length/type
+ combination is encountered. */
+ arg_num++;
+ if (params != 0)
+ params = TREE_CHAIN (params);
+ return false;
+ }
+ 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 (len_modifier.std)
+ && ADJ_STD (wanted_type_std) > ADJ_STD (fci->std))
+ {
+ if (ADJ_STD (wanted_type_std) > C_STD_VER)
+ format_warning_at_char (format_string_loc, format_string_cst,
+ format_chars - orig_format_chars,
+ OPT_Wformat_,
+ "%s does not support the %<%%%s%c%> %s format",
+ C_STD_NAME (wanted_type_std),
+ len_modifier.chars,
+ format_char, fki->name);
+ }
+
+ return true;
+}
+
+/* Check type of argument against desired type.
+
+ Return true if format parsing is to continue, false otherwise. */
+
+bool
+argument_parser::
+check_argument_type (const format_char_info *fci,
+ const length_modifier &len_modifier,
+ tree &wanted_type,
+ const char *&wanted_type_name,
+ const bool suppressed,
+ unsigned HOST_WIDE_INT &arg_num,
+ tree &params,
+ const int alloc_flag,
+ const char * const format_start,
+ const char * const type_start,
+ location_t fmt_param_loc,
+ char conversion_char)
+{
+ if (info->first_arg_num == 0)
+ return true;
+
+ if ((fci->pointer_count == 0 && wanted_type == void_type_node)
+ || suppressed)
+ {
+ if (main_arg_num != 0)
{
- 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_at (format_string_loc, OPT_Wformat_,
- "%s ignored with %s and %<%%%c%> %s format",
- _(s->name), _(t->name), format_char,
- fki->name);
- else
- warning_at (format_string_loc, OPT_Wformat_,
- "%s ignored with %s in %s format",
- _(s->name), _(t->name), fki->name);
- }
+ if (suppressed)
+ warning_at (format_string_loc, OPT_Wformat_,
+ "operand number specified with "
+ "suppressed assignment");
else
- {
- if (bad_flag_pairs[i].predicate != 0)
- warning_at (format_string_loc, OPT_Wformat_,
- "use of %s and %s together with %<%%%c%> %s format",
- _(s->name), _(t->name), format_char,
- fki->name);
- else
- warning_at (format_string_loc, OPT_Wformat_,
- "use of %s and %s together in %s format",
- _(s->name), _(t->name), fki->name);
- }
+ warning_at (format_string_loc, OPT_Wformat_,
+ "operand number specified for format "
+ "taking no argument");
}
+ }
+ else
+ {
+ format_wanted_type *wanted_type_ptr;
- /* Give Y2K warnings. */
- if (warn_format_y2k)
+ if (main_arg_num != 0)
{
- 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_at (format_string_loc, OPT_Wformat_y2k,
- "%<%%%c%> yields only last 2 digits of "
- "year in some locales", format_char);
- else if (y2k_level == 2)
- warning_at (format_string_loc, OPT_Wformat_y2k,
- "%<%%%c%> yields only last 2 digits of year",
- format_char);
+ arg_num = main_arg_num;
+ params = main_arg_params;
}
-
- if (strchr (fci->flags2, '[') != 0)
+ else
{
- /* 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_at (location_from_offset (format_string_loc,
- format_chars - orig_format_chars),
- OPT_Wformat_,
- "no closing %<]%> for %<%%[%> format");
+ ++arg_num;
+ if (has_operand_number > 0)
+ {
+ warning_at (format_string_loc, OPT_Wformat_,
+ "missing $ operand number in format");
+ return false;
+ }
+ else
+ has_operand_number = 0;
}
- wanted_type = 0;
- wanted_type_name = 0;
- if (fki->flags & (int) FMT_FLAG_ARG_CONVERT)
+ wanted_type_ptr = &main_wanted_type;
+ while (fci)
{
- 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)
+ tree cur_param;
+ if (params == 0)
+ cur_param = NULL;
+ else
{
- warning_at (location_from_offset (format_string_loc,
- format_chars - orig_format_chars),
- OPT_Wformat_,
- "use of %qs length modifier with %qc type character"
- " has either no effect or undefined behavior",
- 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;
+ cur_param = TREE_VALUE (params);
+ params = TREE_CHAIN (params);
}
- 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))
+
+ 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 (len_modifier.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 (ADJ_STD (wanted_type_std) > C_STD_VER)
- warning_at (location_from_offset (format_string_loc,
- format_chars - orig_format_chars),
- OPT_Wformat_,
- "%s does not support the %<%%%s%c%> %s format",
- C_STD_NAME (wanted_type_std), length_chars,
- format_char, fki->name);
+ 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->offset_loc = format_chars - orig_format_chars;
+ 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 = fwt_pool.allocate ();
+ arg_num++;
+ wanted_type = *fci->types[len_modifier.val].type;
+ wanted_type_name = fci->types[len_modifier.val].name;
}
}
+ }
- main_wanted_type.next = NULL;
+ if (first_wanted_type != 0)
+ {
+ ptrdiff_t offset_to_format_start = (start_of_this_format - 1) - orig_format_chars;
+ ptrdiff_t offset_to_format_end = (format_chars - 1) - orig_format_chars;
+ /* By default, use the end of the range for the caret location. */
+ substring_loc fmt_loc (fmt_param_loc, TREE_TYPE (format_string_cst),
+ offset_to_format_end,
+ offset_to_format_start, offset_to_format_end);
+ ptrdiff_t offset_to_type_start = type_start - orig_format_chars;
+ check_format_types (fmt_loc, first_wanted_type, fki,
+ offset_to_type_start,
+ conversion_char);
+ }
- /* Finally. . .check type of argument against desired type! */
- if (info->first_arg_num == 0)
+ return true;
+}
+
+/* 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,
+ location_t fmt_param_loc, tree format_string_cst,
+ int format_length, tree params,
+ unsigned HOST_WIDE_INT arg_num,
+ object_allocator <format_wanted_type> &fwt_pool)
+{
+ const char * const orig_format_chars = format_chars;
+ const tree first_fillin_param = params;
+
+ const format_kind_info * const fki = &format_types[info->format_type];
+ const format_flag_spec * const flag_specs = fki->flag_specs;
+ const location_t format_string_loc = res->format_string_loc;
+
+ /* -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)
+ {
+ if (*format_chars++ != '%')
continue;
- if ((fci->pointer_count == 0 && wanted_type == void_type_node)
- || suppressed)
+ if (*format_chars == 0)
{
- if (main_arg_num != 0)
- {
- if (suppressed)
- warning_at (format_string_loc, OPT_Wformat_,
- "operand number specified with "
- "suppressed assignment");
- else
- warning_at (format_string_loc, OPT_Wformat_,
- "operand number specified for format "
- "taking no argument");
- }
+ format_warning_at_char (format_string_loc, format_string_cst,
+ format_chars - orig_format_chars,
+ OPT_Wformat_,
+ "spurious trailing %<%%%> in format");
+ continue;
}
- else
+ if (*format_chars == '%')
{
- format_wanted_type *wanted_type_ptr;
+ ++format_chars;
+ continue;
+ }
- if (main_arg_num != 0)
- {
- arg_num = main_arg_num;
- params = main_arg_params;
- }
- else
- {
- ++arg_num;
- if (has_operand_number > 0)
- {
- warning_at (format_string_loc, OPT_Wformat_,
- "missing $ operand number in format");
- return;
- }
- else
- has_operand_number = 0;
- }
+ flag_chars_t flag_chars;
+ argument_parser arg_parser (info, format_chars, format_string_cst,
+ orig_format_chars, format_string_loc,
+ flag_chars, has_operand_number,
+ first_fillin_param, fwt_pool);
- 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->offset_loc = format_chars - orig_format_chars;
- 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 = fwt_pool.allocate ();
- arg_num++;
- wanted_type = *fci->types[length_chars_val].type;
- wanted_type_name = fci->types[length_chars_val].name;
- }
- }
+ if (!arg_parser.read_any_dollar ())
+ return;
+
+ if (!arg_parser.read_format_flags ())
+ return;
+
+ /* Read any format width, possibly * or *m$. */
+ if (!arg_parser.read_any_format_width (params, arg_num))
+ return;
+
+ /* Read any format left precision (must be a number, not *). */
+ arg_parser.read_any_format_left_precision ();
+
+ /* Read any format precision, possibly * or *m$. */
+ if (!arg_parser.read_any_format_precision (params, arg_num))
+ return;
+
+ const char *format_start = format_chars;
+
+ arg_parser.handle_alloc_chars ();
+
+ /* The rest of the conversion specification is the length modifier
+ (if any), and the conversion specifier, so this is where the
+ type information starts. If we need to issue a suggestion
+ about a type mismatch, then we should preserve everything up
+ to here. */
+ const char *type_start = format_chars;
+
+ /* Read any length modifier, if this kind of format has them. */
+ const length_modifier len_modifier
+ = arg_parser.read_any_length_modifier ();
+
+ /* Read any modifier (strftime E/O). */
+ arg_parser.read_any_other_modifier ();
+
+ char format_char = *format_chars;
+ if (format_char == 0
+ || (!(fki->flags & (int) FMT_FLAG_FANCY_PERCENT_OK)
+ && format_char == '%'))
+ {
+ format_warning_at_char (format_string_loc, format_string_cst,
+ format_chars - orig_format_chars,
+ OPT_Wformat_,
+ "conversion lacks type at end of format");
+ continue;
}
+ format_chars++;
+
+ const format_char_info * const fci
+ = arg_parser.find_format_char_info (format_char);
+ if (!fci)
+ continue;
+
+ flag_chars.validate (fki, fci, flag_specs, format_chars,
+ format_string_cst,
+ format_string_loc, orig_format_chars, format_char);
+
+ const int alloc_flag = flag_chars.get_alloc_flag (fki);
+ const bool suppressed = flag_chars.assignment_suppression_p (fki);
+
+ /* Validate the pairs of flags used. */
+ arg_parser.validate_flag_pairs (fci, format_char);
+
+ arg_parser.give_y2k_warnings (fci, format_char);
+
+ arg_parser.parse_any_scan_set (fci);
- if (first_wanted_type != 0)
- check_format_types (format_string_loc, first_wanted_type);
+ tree wanted_type = NULL;
+ const char *wanted_type_name = NULL;
+
+ if (!arg_parser.handle_conversions (fci, len_modifier,
+ wanted_type, wanted_type_name,
+ arg_num,
+ params,
+ format_char))
+ continue;
+
+ arg_parser.main_wanted_type.next = NULL;
+
+ /* Finally. . .check type of argument against desired type! */
+ if (!arg_parser.check_argument_type (fci, len_modifier,
+ wanted_type, wanted_type_name,
+ suppressed,
+ arg_num, params,
+ alloc_flag,
+ format_start, type_start,
+ fmt_param_loc,
+ format_char))
+ return;
}
if (format_chars - orig_format_chars != format_length)
- warning_at (location_from_offset (format_string_loc,
- format_chars + 1 - orig_format_chars),
- OPT_Wformat_contains_nul,
- "embedded %<\\0%> in format");
+ format_warning_at_char (format_string_loc, format_string_cst,
+ format_chars + 1 - orig_format_chars,
+ OPT_Wformat_contains_nul,
+ "embedded %<\\0%> in format");
if (info->first_arg_num != 0 && params != 0
&& has_operand_number <= 0)
{
@@ -2439,12 +2836,59 @@ check_format_info_main (format_check_results *res,
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). LOC is the location of
- the format string. */
+ including width and precision arguments).
+
+ FMT_LOC is the location of the format conversion.
+
+ TYPES is a singly-linked list expressing the parts of the format
+ conversion that expect argument types, and the arguments they
+ correspond to.
+
+ OFFSET_TO_TYPE_START is the offset within the execution-charset encoded
+ format string to where type information begins for the conversion
+ (the length modifier and conversion specifier).
+
+ CONVERSION_CHAR is the user-provided conversion specifier.
+
+ For example, given:
+
+ sprintf (d, "before %-+*.*lld after", arg3, arg4, arg5);
+
+ then FMT_LOC covers this range:
+
+ sprintf (d, "before %-+*.*lld after", arg3, arg4, arg5);
+ ^^^^^^^^^
+
+ and TYPES in this case is a three-entry singly-linked list consisting of:
+ (1) the check for the field width here:
+ sprintf (d, "before %-+*.*lld after", arg3, arg4, arg5);
+ ^ ^^^^
+ against arg3, and
+ (2) the check for the field precision here:
+ sprintf (d, "before %-+*.*lld after", arg3, arg4, arg5);
+ ^^ ^^^^
+ against arg4, and
+ (3) the check for the length modifier and conversion char here:
+ sprintf (d, "before %-+*.*lld after", arg3, arg4, arg5);
+ ^^^ ^^^^
+ against arg5.
+
+ OFFSET_TO_TYPE_START is 13, the offset to the "lld" within the
+ STRING_CST:
+
+ 0000000000111111111122
+ 0123456789012345678901
+ sprintf (d, "before %-+*.*lld after", arg3, arg4, arg5);
+ ^ ^
+ | ` CONVERSION_CHAR: 'd'
+ type starts here. */
+
static void
-check_format_types (location_t loc, format_wanted_type *types)
+check_format_types (const substring_loc &fmt_loc,
+ format_wanted_type *types, const format_kind_info *fki,
+ int offset_to_type_start,
+ char conversion_char)
{
for (; types != 0; types = types->next)
{
@@ -2471,7 +2915,8 @@ check_format_types (location_t loc, format_wanted_type *types)
cur_param = types->param;
if (!cur_param)
{
- format_type_warning (loc, types, wanted_type, NULL);
+ format_type_warning (fmt_loc, NULL, types, wanted_type, NULL, fki,
+ offset_to_type_start, conversion_char);
continue;
}
@@ -2481,6 +2926,16 @@ check_format_types (location_t loc, format_wanted_type *types)
orig_cur_type = cur_type;
char_type_flag = 0;
+ source_range param_range;
+ source_range *param_range_ptr;
+ if (CAN_HAVE_LOCATION_P (cur_param))
+ {
+ param_range = EXPR_LOCATION_RANGE (cur_param);
+ param_range_ptr = &param_range;
+ }
+ else
+ param_range_ptr = NULL;
+
STRIP_NOPS (cur_param);
/* Check the types of any additional pointer arguments
@@ -2545,7 +3000,9 @@ check_format_types (location_t loc, format_wanted_type *types)
}
else
{
- format_type_warning (loc, types, wanted_type, orig_cur_type);
+ format_type_warning (fmt_loc, param_range_ptr,
+ types, wanted_type, orig_cur_type, fki,
+ offset_to_type_start, conversion_char);
break;
}
}
@@ -2613,29 +3070,351 @@ check_format_types (location_t loc, format_wanted_type *types)
&& TYPE_PRECISION (cur_type) == TYPE_PRECISION (wanted_type))
continue;
/* Now we have a type mismatch. */
- format_type_warning (loc, types, wanted_type, orig_cur_type);
+ format_type_warning (fmt_loc, param_range_ptr, types,
+ wanted_type, orig_cur_type, fki,
+ offset_to_type_start, conversion_char);
}
}
+/* Given type TYPE, attempt to dereference the type N times
+ (e.g. from ("int ***", 2) to "int *")
+
+ Return the derefenced type, with any qualifiers
+ such as "const" stripped from the result, or
+ NULL if unsuccessful (e.g. TYPE is not a pointer type). */
+
+static tree
+deref_n_times (tree type, int n)
+{
+ gcc_assert (type);
+
+ for (int i = n; i > 0; i--)
+ {
+ if (TREE_CODE (type) != POINTER_TYPE)
+ return NULL_TREE;
+ type = TREE_TYPE (type);
+ }
+ /* Strip off any "const" etc. */
+ return build_qualified_type (type, 0);
+}
+
+/* Lookup the format code for FORMAT_LEN within FLI,
+ returning the string code for expressing it, or NULL
+ if it is not found. */
+
+static const char *
+get_modifier_for_format_len (const format_length_info *fli,
+ enum format_lengths format_len)
+{
+ for (; fli->name; fli++)
+ {
+ if (fli->index == format_len)
+ return fli->name;
+ if (fli->double_index == format_len)
+ return fli->double_name;
+ }
+ return NULL;
+}
+
+#if CHECKING_P
+
+namespace selftest {
+
+static void
+test_get_modifier_for_format_len ()
+{
+ ASSERT_STREQ ("h",
+ get_modifier_for_format_len (printf_length_specs, FMT_LEN_h));
+ ASSERT_STREQ ("hh",
+ get_modifier_for_format_len (printf_length_specs, FMT_LEN_hh));
+ ASSERT_STREQ ("L",
+ get_modifier_for_format_len (printf_length_specs, FMT_LEN_L));
+ ASSERT_EQ (NULL,
+ get_modifier_for_format_len (printf_length_specs, FMT_LEN_none));
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
+
+/* Determine if SPEC_TYPE and ARG_TYPE are sufficiently similar for a
+ format_type_detail using SPEC_TYPE to be offered as a suggestion for
+ Wformat type errors where the argument has type ARG_TYPE. */
+
+static bool
+matching_type_p (tree spec_type, tree arg_type)
+{
+ gcc_assert (spec_type);
+ gcc_assert (arg_type);
+
+ spec_type = TYPE_CANONICAL (spec_type);
+ arg_type = TYPE_CANONICAL (arg_type);
+
+ if (TREE_CODE (spec_type) == INTEGER_TYPE
+ && TREE_CODE (arg_type) == INTEGER_TYPE
+ && (TYPE_UNSIGNED (spec_type)
+ ? spec_type == c_common_unsigned_type (arg_type)
+ : spec_type == c_common_signed_type (arg_type)))
+ return true;
+
+ return spec_type == arg_type;
+}
+
+/* Subroutine of get_format_for_type.
+
+ Generate a string containing the length modifier and conversion specifier
+ that should be used to format arguments of type ARG_TYPE within FKI
+ (effectively the inverse of the checking code).
+
+ If CONVERSION_CHAR is not zero (the first pass), the resulting suggestion
+ is required to use it, for correcting bogus length modifiers.
+ If CONVERSION_CHAR is zero (the second pass), then allow any suggestion
+ that matches ARG_TYPE.
+
+ If successful, returns a non-NULL string which should be freed
+ by the caller.
+ Otherwise, returns NULL. */
+
+static char *
+get_format_for_type_1 (const format_kind_info *fki, tree arg_type,
+ char conversion_char)
+{
+ gcc_assert (arg_type);
+
+ const format_char_info *spec;
+ for (spec = &fki->conversion_specs[0];
+ spec->format_chars;
+ spec++)
+ {
+ if (conversion_char)
+ if (!strchr (spec->format_chars, conversion_char))
+ continue;
+
+ tree effective_arg_type = deref_n_times (arg_type,
+ spec->pointer_count);
+ if (!effective_arg_type)
+ continue;
+ for (int i = 0; i < FMT_LEN_MAX; i++)
+ {
+ const format_type_detail *ftd = &spec->types[i];
+ if (!ftd->type)
+ continue;
+ if (matching_type_p (*ftd->type, effective_arg_type))
+ {
+ const char *len_modifier
+ = get_modifier_for_format_len (fki->length_char_specs,
+ (enum format_lengths)i);
+ if (!len_modifier)
+ len_modifier = "";
+
+ if (conversion_char)
+ /* We found a match, using the given conversion char - the
+ length modifier was incorrect (or absent).
+ Provide a suggestion using the conversion char with the
+ correct length modifier for the type. */
+ return xasprintf ("%s%c", len_modifier, conversion_char);
+ else
+ /* 2nd pass: no match was possible using the user-provided
+ conversion char, but we do have a match without using it.
+ Provide a suggestion using the first conversion char
+ listed for the given type. */
+ return xasprintf ("%s%c", len_modifier, spec->format_chars[0]);
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/* Generate a string containing the length modifier and conversion specifier
+ that should be used to format arguments of type ARG_TYPE within FKI
+ (effectively the inverse of the checking code).
+
+ If successful, returns a non-NULL string which should be freed
+ by the caller.
+ Otherwise, returns NULL. */
+
+static char *
+get_format_for_type (const format_kind_info *fki, tree arg_type,
+ char conversion_char)
+{
+ gcc_assert (arg_type);
+ gcc_assert (conversion_char);
+
+ /* First pass: look for a format_char_info containing CONVERSION_CHAR
+ If we find one, then presumably the length modifier was incorrect
+ (or absent). */
+ char *result = get_format_for_type_1 (fki, arg_type, conversion_char);
+ if (result)
+ return result;
+
+ /* Second pass: we didn't find a match for CONVERSION_CHAR, so try
+ matching just on the type. */
+ return get_format_for_type_1 (fki, arg_type, '\0');
+}
+
+/* Attempt to get a string for use as a replacement fix-it hint for the
+ source range in FMT_LOC.
+
+ Preserve all of the text within the range of FMT_LOC up to
+ OFFSET_TO_TYPE_START, replacing the rest with an appropriate
+ length modifier and conversion specifier for ARG_TYPE, attempting
+ to keep the user-provided CONVERSION_CHAR if possible.
+
+ For example, given a long vs long long mismatch for arg5 here:
+
+ 000000000111111111122222222223333333333|
+ 123456789012345678901234567890123456789` column numbers
+ 0000000000111111111122|
+ 0123456789012345678901` string offsets
+ V~~~~~~~~ : range of FMT_LOC, from cols 23-31
+ sprintf (d, "before %-+*.*lld after", arg3, arg4, arg5);
+ ^ ^
+ | ` CONVERSION_CHAR: 'd'
+ type starts here
+
+ where OFFSET_TO_TYPE_START is 13 (the offset to the "lld" within the
+ STRING_CST), where the user provided:
+ %-+*.*lld
+ the result (assuming "long" argument 5) should be:
+ %-+*.*ld
+
+ If successful, returns a non-NULL string which should be freed
+ by the caller.
+ Otherwise, returns NULL. */
+
+static char *
+get_corrected_substring (const substring_loc &fmt_loc,
+ format_wanted_type *type, tree arg_type,
+ const format_kind_info *fki,
+ int offset_to_type_start, char conversion_char)
+{
+ /* Attempt to provide hints for argument types, but not for field widths
+ and precisions. */
+ if (!arg_type)
+ return NULL;
+ if (type->kind != CF_KIND_FORMAT)
+ return NULL;
+
+ /* Locate the current code within the source range, rejecting
+ any awkward cases where the format string occupies more than
+ one line.
+ Lookup the place where the type starts (including any length
+ modifiers), getting it as the caret location. */
+ substring_loc type_loc (fmt_loc);
+ type_loc.set_caret_index (offset_to_type_start);
+
+ location_t fmt_substring_loc;
+ const char *err = type_loc.get_location (&fmt_substring_loc);
+ if (err)
+ return NULL;
+
+ source_range fmt_substring_range
+ = get_range_from_loc (line_table, fmt_substring_loc);
+
+ expanded_location caret
+ = expand_location_to_spelling_point (fmt_substring_loc);
+ expanded_location start
+ = expand_location_to_spelling_point (fmt_substring_range.m_start);
+ expanded_location finish
+ = expand_location_to_spelling_point (fmt_substring_range.m_finish);
+ if (caret.file != start.file)
+ return NULL;
+ if (start.file != finish.file)
+ return NULL;
+ if (caret.line != start.line)
+ return NULL;
+ if (start.line != finish.line)
+ return NULL;
+ if (start.column > caret.column)
+ return NULL;
+ if (start.column > finish.column)
+ return NULL;
+ if (caret.column > finish.column)
+ return NULL;
-/* Give a warning at LOC 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
+ int line_width;
+ const char *line = location_get_source_line (start.file, start.line,
+ &line_width);
+ if (line == NULL)
+ return NULL;
+
+ /* If we got this far, then we have the line containing the
+ existing conversion specification.
+
+ Generate a trimmed copy, containing the prefix part of the conversion
+ specification, up to the (but not including) the length modifier.
+ In the above example, this would be "%-+*.*". */
+ const char *current_content = line + start.column - 1;
+ int length_up_to_type = caret.column - start.column;
+ char *prefix = xstrndup (current_content, length_up_to_type);
+
+ /* Now attempt to generate a suggestion for the rest of the specification
+ (length modifier and conversion char), based on ARG_TYPE and
+ CONVERSION_CHAR.
+ In the above example, this would be "ld". */
+ char *format_for_type = get_format_for_type (fki, arg_type, conversion_char);
+ if (!format_for_type)
+ {
+ free (prefix);
+ return NULL;
+ }
+
+ /* Success. Generate the resulting suggestion for the whole range of
+ FMT_LOC by concatenating the two strings.
+ In the above example, this would be "%-+*.*ld". */
+ char *result = concat (prefix, format_for_type, NULL);
+ free (format_for_type);
+ free (prefix);
+ return result;
+}
+
+/* Give a warning about a format argument of different type from that expected.
+ The range of the diagnostic is taken from WHOLE_FMT_LOC; the caret location
+ is based on the location of the char at TYPE->offset_loc.
+ If non-NULL, PARAM_RANGE is the source range of the
+ relevant argument. 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. */
+ or NULL if it is missing.
+
+ OFFSET_TO_TYPE_START is the offset within the execution-charset encoded
+ format string to where type information begins for the conversion
+ (the length modifier and conversion specifier).
+ CONVERSION_CHAR is the user-provided conversion specifier.
+
+ For example, given a type mismatch for argument 5 here:
+
+ 00000000011111111112222222222333333333344444444445555555555|
+ 12345678901234567890123456789012345678901234567890123456789` column numbers
+ 0000000000111111111122|
+ 0123456789012345678901` offsets within STRING_CST
+ V~~~~~~~~ : range of WHOLE_FMT_LOC, from cols 23-31
+ sprintf (d, "before %-+*.*lld after", int_expr, int_expr, long_expr);
+ ^ ^ ^~~~~~~~~
+ | ` CONVERSION_CHAR: 'd' *PARAM_RANGE
+ type starts here
+
+ OFFSET_TO_TYPE_START is 13, the offset to the "lld" within the
+ STRING_CST. */
+
static void
-format_type_warning (location_t loc, format_wanted_type *type,
- tree wanted_type, tree arg_type)
+format_type_warning (const substring_loc &whole_fmt_loc,
+ source_range *param_range,
+ format_wanted_type *type,
+ tree wanted_type, tree arg_type,
+ const format_kind_info *fki,
+ int offset_to_type_start,
+ char conversion_char)
{
- int kind = type->kind;
+ enum format_specifier_kind 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;
- unsigned int offset_loc = type->offset_loc;
char *p;
/* If ARG_TYPE is a typedef with a misleading name (for example,
@@ -2669,42 +3448,62 @@ format_type_warning (location_t loc, format_wanted_type *type,
p[pointer_count + 1] = 0;
}
- loc = location_from_offset (loc, offset_loc);
-
+ /* WHOLE_FMT_LOC has the caret at the end of the range.
+ Set the caret to be at the offset from TYPE. Subtract one
+ from the offset for the same reason as in format_warning_at_char. */
+ substring_loc fmt_loc (whole_fmt_loc);
+ fmt_loc.set_caret_index (type->offset_loc - 1);
+
+ /* Get a string for use as a replacement fix-it hint for the range in
+ fmt_loc, or NULL. */
+ char *corrected_substring
+ = get_corrected_substring (fmt_loc, type, arg_type, fki,
+ offset_to_type_start, conversion_char);
+
if (wanted_type_name)
{
if (arg_type)
- warning_at (loc, 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);
+ format_warning_at_substring
+ (fmt_loc, param_range,
+ corrected_substring, 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_at (loc, 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);
+ format_warning_at_substring
+ (fmt_loc, param_range,
+ corrected_substring, 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_at (loc, 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);
+ format_warning_at_substring
+ (fmt_loc, param_range,
+ corrected_substring, 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_at (loc, 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);
+ format_warning_at_substring
+ (fmt_loc, param_range,
+ corrected_substring, 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);
}
+
+ free (corrected_substring);
}
@@ -3225,3 +4024,118 @@ handle_format_attribute (tree *node, tree ARG_UNUSED (name), tree args,
return NULL_TREE;
}
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Selftests of location handling. */
+
+/* Get the format_kind_info with the given name. */
+
+static const format_kind_info *
+get_info (const char *name)
+{
+ int idx = decode_format_type (name);
+ const format_kind_info *fki = &format_types[idx];
+ ASSERT_STREQ (fki->name, name);
+ return fki;
+}
+
+/* Verify that get_format_for_type (FKI, TYPE, CONVERSION_CHAR)
+ is EXPECTED_FORMAT. */
+
+static void
+assert_format_for_type_streq (const location &loc, const format_kind_info *fki,
+ const char *expected_format, tree type,
+ char conversion_char)
+{
+ gcc_assert (fki);
+ gcc_assert (expected_format);
+ gcc_assert (type);
+
+ char *actual_format = get_format_for_type (fki, type, conversion_char);
+ ASSERT_STREQ_AT (loc, expected_format, actual_format);
+ free (actual_format);
+}
+
+/* Selftests for get_format_for_type. */
+
+#define ASSERT_FORMAT_FOR_TYPE_STREQ(EXPECTED_FORMAT, TYPE, CONVERSION_CHAR) \
+ assert_format_for_type_streq (SELFTEST_LOCATION, (fki), (EXPECTED_FORMAT), \
+ (TYPE), (CONVERSION_CHAR))
+
+/* Selftest for get_format_for_type for "printf"-style functions. */
+
+static void
+test_get_format_for_type_printf ()
+{
+ const format_kind_info *fki = get_info ("gnu_printf");
+ ASSERT_NE (fki, NULL);
+
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("f", double_type_node, 'i');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("Lf", long_double_type_node, 'i');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("f", double_type_node, 'o');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("Lf", long_double_type_node, 'o');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("f", double_type_node, 'x');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("Lf", long_double_type_node, 'x');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("f", double_type_node, 'X');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("Lf", long_double_type_node, 'X');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("d", integer_type_node, 'd');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("i", integer_type_node, 'i');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("o", integer_type_node, 'o');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("x", integer_type_node, 'x');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("X", integer_type_node, 'X');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("d", unsigned_type_node, 'd');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("i", unsigned_type_node, 'i');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("o", unsigned_type_node, 'o');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("x", unsigned_type_node, 'x');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("X", unsigned_type_node, 'X');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("ld", long_integer_type_node, 'd');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("li", long_integer_type_node, 'i');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("lx", long_integer_type_node, 'x');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("lo", long_unsigned_type_node, 'o');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("lx", long_unsigned_type_node, 'x');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("lld", long_long_integer_type_node, 'd');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("lli", long_long_integer_type_node, 'i');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("llo", long_long_unsigned_type_node, 'o');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("llx", long_long_unsigned_type_node, 'x');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("s", build_pointer_type (char_type_node), 'i');
+}
+
+/* Selftest for get_format_for_type for "scanf"-style functions. */
+
+static void
+test_get_format_for_type_scanf ()
+{
+ const format_kind_info *fki = get_info ("gnu_scanf");
+ ASSERT_NE (fki, NULL);
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("d", build_pointer_type (integer_type_node), 'd');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("u", build_pointer_type (unsigned_type_node), 'u');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("ld",
+ build_pointer_type (long_integer_type_node), 'd');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("lu",
+ build_pointer_type (long_unsigned_type_node), 'u');
+ ASSERT_FORMAT_FOR_TYPE_STREQ
+ ("lld", build_pointer_type (long_long_integer_type_node), 'd');
+ ASSERT_FORMAT_FOR_TYPE_STREQ
+ ("llu", build_pointer_type (long_long_unsigned_type_node), 'u');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("e", build_pointer_type (float_type_node), 'e');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("le", build_pointer_type (double_type_node), 'e');
+}
+
+#undef ASSERT_FORMAT_FOR_TYPE_STREQ
+
+/* Run all of the selftests within this file. */
+
+void
+c_format_c_tests ()
+{
+ test_get_modifier_for_format_len ();
+ test_get_format_for_type_printf ();
+ test_get_format_for_type_scanf ();
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
diff --git a/gcc/c-family/c-format.h b/gcc/c-family/c-format.h
index edbd4a1a12..13ca8eadbe 100644
--- a/gcc/c-family/c-format.h
+++ b/gcc/c-family/c-format.h
@@ -1,5 +1,5 @@
/* Check calls to formatted I/O functions (-Wformat).
- Copyright (C) 1992-2016 Free Software Foundation, Inc.
+ Copyright (C) 1992-2017 Free Software Foundation, Inc.
This file is part of GCC.
diff --git a/gcc/c-family/c-gimplify.c b/gcc/c-family/c-gimplify.c
index c18b057727..57edb41af0 100644
--- a/gcc/c-family/c-gimplify.c
+++ b/gcc/c-family/c-gimplify.c
@@ -2,7 +2,7 @@
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-2016 Free Software Foundation, Inc.
+ Copyright (C) 2002-2017 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>
@@ -125,6 +125,10 @@ c_genericize (tree fndecl)
&pset);
}
+ if (warn_duplicated_branches)
+ walk_tree_without_duplicates (&DECL_SAVED_TREE (fndecl),
+ do_warn_duplicated_branches_r, NULL);
+
/* Dump the C-specific tree IR. */
dump_orig = get_dump_info (TDI_original, &local_dump_flags);
if (dump_orig)
diff --git a/gcc/c-family/c-indentation.c b/gcc/c-family/c-indentation.c
index 8c336867d8..8300788db1 100644
--- a/gcc/c-family/c-indentation.c
+++ b/gcc/c-family/c-indentation.c
@@ -1,5 +1,5 @@
/* Implementation of -Wmisleading-indentation
- Copyright (C) 2015-2016 Free Software Foundation, Inc.
+ Copyright (C) 2015-2017 Free Software Foundation, Inc.
This file is part of GCC.
@@ -607,8 +607,8 @@ warn_for_misleading_indentation (const token_indent_info &guard_tinfo,
"this %qs clause does not guard...",
guard_tinfo_to_string (guard_tinfo)))
inform (next_tinfo.location,
- ("...this statement, but the latter is misleadingly indented"
- " as if it is guarded by the %qs"),
+ "...this statement, but the latter is misleadingly indented"
+ " as if it were guarded by the %qs",
guard_tinfo_to_string (guard_tinfo));
}
}
diff --git a/gcc/c-family/c-indentation.h b/gcc/c-family/c-indentation.h
index 0ea486b11e..a4366971e9 100644
--- a/gcc/c-family/c-indentation.h
+++ b/gcc/c-family/c-indentation.h
@@ -1,5 +1,5 @@
/* Definitions for c-indentation.c.
- Copyright (C) 2015-2016 Free Software Foundation, Inc.
+ Copyright (C) 2015-2017 Free Software Foundation, Inc.
This file is part of GCC.
diff --git a/gcc/c-family/c-lex.c b/gcc/c-family/c-lex.c
index 96da4fc974..e1c8bdff98 100644
--- a/gcc/c-family/c-lex.c
+++ b/gcc/c-family/c-lex.c
@@ -1,5 +1,5 @@
/* Mainly the interface between cpplib and the C front ends.
- Copyright (C) 1987-2016 Free Software Foundation, Inc.
+ Copyright (C) 1987-2017 Free Software Foundation, Inc.
This file is part of GCC.
@@ -80,6 +80,8 @@ init_c_lex (void)
cb->valid_pch = c_common_valid_pch;
cb->read_pch = c_common_read_pch;
cb->has_attribute = c_common_has_attribute;
+ cb->get_source_date_epoch = cb_get_source_date_epoch;
+ cb->get_suggestion = cb_get_suggestion;
/* Set the debug callbacks if we can use them. */
if ((debug_info_level == DINFO_LEVEL_VERBOSE
@@ -340,23 +342,28 @@ c_common_has_attribute (cpp_reader *pfile)
attr_name = NULL_TREE;
}
}
- }
- if (attr_name)
- {
- init_attributes ();
- const struct attribute_spec *attr = lookup_attribute_spec (attr_name);
- if (attr)
+ else
{
- if (TREE_CODE (attr_name) == TREE_LIST)
- attr_name = TREE_VALUE (attr_name);
+ /* Some standard attributes need special handling. */
if (is_attribute_p ("noreturn", attr_name))
result = 200809;
else if (is_attribute_p ("deprecated", attr_name))
result = 201309;
- else
- result = 1;
+ else if (is_attribute_p ("maybe_unused", attr_name)
+ || is_attribute_p ("nodiscard", attr_name)
+ || is_attribute_p ("fallthrough", attr_name))
+ result = 201603;
+ if (result)
+ attr_name = NULL_TREE;
}
}
+ if (attr_name)
+ {
+ init_attributes ();
+ const struct attribute_spec *attr = lookup_attribute_spec (attr_name);
+ if (attr)
+ result = 1;
+ }
}
else
{
@@ -589,9 +596,21 @@ c_lex_with_flags (tree *value, location_t *loc, unsigned char *cpp_flags,
case CPP_MACRO_ARG:
gcc_unreachable ();
- /* CPP_COMMENT will appear when compiling with -C and should be
- ignored. */
- case CPP_COMMENT:
+ /* CPP_COMMENT will appear when compiling with -C. Ignore, except
+ when it is a FALLTHROUGH comment, in that case set
+ PREV_FALLTHROUGH flag on the next non-comment token. */
+ case CPP_COMMENT:
+ if (tok->flags & PREV_FALLTHROUGH)
+ {
+ do
+ {
+ tok = cpp_get_token_with_location (parse_in, loc);
+ type = tok->type;
+ }
+ while (type == CPP_PADDING || type == CPP_COMMENT);
+ add_flags |= PREV_FALLTHROUGH;
+ goto retry_after_at;
+ }
goto retry;
default:
@@ -834,6 +853,26 @@ interpret_float (const cpp_token *token, unsigned int flags,
type = c_common_type_for_mode (mode, 0);
gcc_assert (type);
}
+ else if ((flags & (CPP_N_FLOATN | CPP_N_FLOATNX)) != 0)
+ {
+ unsigned int n = (flags & CPP_N_WIDTH_FLOATN_NX) >> CPP_FLOATN_SHIFT;
+ bool extended = (flags & CPP_N_FLOATNX) != 0;
+ type = NULL_TREE;
+ for (int i = 0; i < NUM_FLOATN_NX_TYPES; i++)
+ if (floatn_nx_types[i].n == (int) n
+ && floatn_nx_types[i].extended == extended)
+ {
+ type = FLOATN_NX_TYPE_NODE (i);
+ break;
+ }
+ if (type == NULL_TREE)
+ {
+ error ("unsupported non-standard suffix on floating constant");
+ return error_mark_node;
+ }
+ else
+ pedwarn (input_location, OPT_Wpedantic, "non-standard suffix on floating constant");
+ }
else if ((flags & CPP_N_WIDTH) == CPP_N_LARGE)
type = long_double_type_node;
else if ((flags & CPP_N_WIDTH) == CPP_N_SMALL
@@ -862,6 +901,17 @@ interpret_float (const cpp_token *token, unsigned int flags,
if (flags & CPP_N_IMAGINARY)
/* I or J suffix. */
copylen--;
+ if (flags & CPP_N_FLOATNX)
+ copylen--;
+ if (flags & (CPP_N_FLOATN | CPP_N_FLOATNX))
+ {
+ unsigned int n = (flags & CPP_N_WIDTH_FLOATN_NX) >> CPP_FLOATN_SHIFT;
+ while (n > 0)
+ {
+ copylen--;
+ n /= 10;
+ }
+ }
}
copy = (char *) alloca (copylen + 1);
@@ -1092,13 +1142,16 @@ lex_string (const cpp_token *tok, tree *valp, bool objc_string, bool translate)
tree value;
size_t concats = 0;
struct obstack str_ob;
+ struct obstack loc_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;
+ location_t init_loc = tok->src_loc;
cpp_string *strs = &str;
+ location_t *locs = NULL;
/* objc_at_sign_was_seen is only used when doing Objective-C string
concatenation. It is 'true' if we have seen an '@' before the
@@ -1137,16 +1190,21 @@ lex_string (const cpp_token *tok, tree *valp, bool objc_string, bool translate)
else
error ("unsupported non-standard concatenation of string literals");
}
+ /* FALLTHROUGH */
case CPP_STRING:
if (!concats)
{
gcc_obstack_init (&str_ob);
+ gcc_obstack_init (&loc_ob);
obstack_grow (&str_ob, &str, sizeof (cpp_string));
+ obstack_grow (&loc_ob, &init_loc, sizeof (location_t));
}
concats++;
obstack_grow (&str_ob, &tok->val.str, sizeof (cpp_string));
+ obstack_grow (&loc_ob, &tok->src_loc, sizeof (location_t));
+
if (objc_string)
objc_at_sign_was_seen = false;
goto retry;
@@ -1159,7 +1217,10 @@ lex_string (const cpp_token *tok, tree *valp, bool objc_string, bool translate)
/* We have read one more token than we want. */
_cpp_backup_tokens (parse_in, 1);
if (concats)
- strs = XOBFINISH (&str_ob, cpp_string *);
+ {
+ strs = XOBFINISH (&str_ob, cpp_string *);
+ locs = XOBFINISH (&loc_ob, location_t *);
+ }
if (concats && !objc_string && !in_system_header_at (input_location))
warning (OPT_Wtraditional,
@@ -1171,6 +1232,12 @@ lex_string (const cpp_token *tok, tree *valp, bool objc_string, bool translate)
{
value = build_string (istr.len, (const char *) istr.text);
free (CONST_CAST (unsigned char *, istr.text));
+ if (concats)
+ {
+ gcc_assert (locs);
+ gcc_assert (g_string_concat_db);
+ g_string_concat_db->record_string_concatenation (concats + 1, locs);
+ }
}
else
{
@@ -1222,7 +1289,10 @@ lex_string (const cpp_token *tok, tree *valp, bool objc_string, bool translate)
*valp = fix_string_type (value);
if (concats)
- obstack_free (&str_ob, 0);
+ {
+ obstack_free (&str_ob, 0);
+ obstack_free (&loc_ob, 0);
+ }
return objc_string ? CPP_OBJC_STRING : type;
}
diff --git a/gcc/c-family/c-objc.h b/gcc/c-family/c-objc.h
index 4e362b3236..dc5f08faaa 100644
--- a/gcc/c-family/c-objc.h
+++ b/gcc/c-family/c-objc.h
@@ -1,5 +1,5 @@
/* Definitions of Objective-C front-end entry points used for C and C++.
- Copyright (C) 1987-2016 Free Software Foundation, Inc.
+ Copyright (C) 1987-2017 Free Software Foundation, Inc.
This file is part of GCC.
diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c
index 1691c40f11..519c4e4ce6 100644
--- a/gcc/c-family/c-omp.c
+++ b/gcc/c-family/c-omp.c
@@ -1,7 +1,7 @@
/* This file contains routines to construct OpenACC and OpenMP constructs,
called from parsing in the C and C++ front ends.
- Copyright (C) 2005-2016 Free Software Foundation, Inc.
+ Copyright (C) 2005-2017 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>,
Diego Novillo <dnovillo@redhat.com>.
@@ -28,7 +28,7 @@ along with GCC; see the file COPYING3. If not see
#include "c-common.h"
#include "gimple-expr.h"
#include "c-pragma.h"
-#include "omp-low.h"
+#include "omp-general.h"
#include "gomp-constants.h"
@@ -45,7 +45,7 @@ c_finish_oacc_wait (location_t loc, tree parms, tree clauses)
vec_alloc (args, nparms + 2);
stmt = builtin_decl_explicit (BUILT_IN_GOACC_WAIT);
- if (find_omp_clause (clauses, OMP_CLAUSE_ASYNC))
+ if (omp_find_clause (clauses, OMP_CLAUSE_ASYNC))
t = OMP_CLAUSE_ASYNC_EXPR (clauses);
else
t = build_int_cst (integer_type_node, GOMP_ASYNC_SYNC);
@@ -199,6 +199,11 @@ c_finish_omp_atomic (location_t loc, enum tree_code code,
error_at (loc, "invalid expression type for %<#pragma omp atomic%>");
return error_mark_node;
}
+ if (TYPE_ATOMIC (type))
+ {
+ error_at (loc, "%<_Atomic%> expression in %<#pragma omp atomic%>");
+ return error_mark_node;
+ }
if (opcode == RDIV_EXPR)
opcode = TRUNC_DIV_EXPR;
@@ -207,7 +212,7 @@ c_finish_omp_atomic (location_t loc, enum tree_code code,
/* 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);
+ addr = build_unary_op (loc, ADDR_EXPR, lhs, false);
if (addr == error_mark_node)
return error_mark_node;
if (!test)
@@ -298,14 +303,14 @@ c_finish_omp_atomic (location_t loc, enum tree_code code,
loc, x, NULL_TREE);
if (rhs1 && rhs1 != lhs)
{
- tree rhs1addr = build_unary_op (loc, ADDR_EXPR, rhs1, 0);
+ tree rhs1addr = build_unary_op (loc, ADDR_EXPR, rhs1, false);
if (rhs1addr == error_mark_node)
return error_mark_node;
x = omit_one_operand_loc (loc, type, x, rhs1addr);
}
if (lhs1 && lhs1 != lhs)
{
- tree lhs1addr = build_unary_op (loc, ADDR_EXPR, lhs1, 0);
+ tree lhs1addr = build_unary_op (loc, ADDR_EXPR, lhs1, false);
if (lhs1addr == error_mark_node)
return error_mark_node;
if (code == OMP_ATOMIC_CAPTURE_OLD)
@@ -320,7 +325,7 @@ c_finish_omp_atomic (location_t loc, enum tree_code code,
}
else if (rhs1 && rhs1 != lhs)
{
- tree rhs1addr = build_unary_op (loc, ADDR_EXPR, rhs1, 0);
+ tree rhs1addr = build_unary_op (loc, ADDR_EXPR, rhs1, false);
if (rhs1addr == error_mark_node)
return error_mark_node;
x = omit_one_operand_loc (loc, type, x, rhs1addr);
@@ -480,6 +485,14 @@ c_finish_omp_for (location_t locus, enum tree_code code, tree declv,
error_at (elocus, "invalid type for iteration variable %qE", decl);
fail = true;
}
+ else if (TYPE_ATOMIC (TREE_TYPE (decl)))
+ {
+ error_at (elocus, "%<_Atomic%> iteration variable %qE", decl);
+ fail = true;
+ /* _Atomic iterator confuses stuff too much, so we risk ICE
+ trying to diagnose it further. */
+ continue;
+ }
/* 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. */
diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c
index fec58bcf91..7dea165740 100644
--- a/gcc/c-family/c-opts.c
+++ b/gcc/c-family/c-opts.c
@@ -1,5 +1,5 @@
/* C/ObjC/C++ command line option handling.
- Copyright (C) 2002-2016 Free Software Foundation, Inc.
+ Copyright (C) 2002-2017 Free Software Foundation, Inc.
Contributed by Neil Booth.
This file is part of GCC.
@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3. If not see
#include "tm.h"
#include "c-target.h"
#include "c-common.h"
+#include "memmodel.h"
#include "tm_p.h" /* For C_COMMON_OVERRIDE_OPTIONS. */
#include "diagnostic.h"
#include "c-pragma.h"
@@ -164,7 +165,7 @@ static void
c_diagnostic_finalizer (diagnostic_context *context,
diagnostic_info *diagnostic)
{
- diagnostic_show_locus (context, diagnostic);
+ diagnostic_show_locus (context, diagnostic->richloc, diagnostic->kind);
/* By default print macro expansion contexts in the diagnostic
finalizer -- for tokens resulting from macro expansion. */
virt_loc_aware_diagnostic_finalizer (context, diagnostic);
@@ -216,6 +217,9 @@ c_common_init_options (unsigned int decoded_options_count,
unsigned int i;
struct cpp_callbacks *cb;
+ g_string_concat_db
+ = new (ggc_alloc <string_concat_db> ()) string_concat_db ();
+
parse_in = cpp_create_reader (c_dialect_cxx () ? CLK_GNUCXX: CLK_GNUC89,
ident_hash, line_table);
cb = cpp_get_callbacks (parse_in);
@@ -376,6 +380,16 @@ c_common_handle_option (size_t scode, const char *arg, int value,
cpp_opts->warn_num_sign_change = value;
break;
+ case OPT_Walloca_larger_than_:
+ if (!value)
+ inform (loc, "-Walloca-larger-than=0 is meaningless");
+ break;
+
+ case OPT_Wvla_larger_than_:
+ if (!value)
+ inform (loc, "-Wvla-larger-than=0 is meaningless");
+ break;
+
case OPT_Wunknown_pragmas:
/* Set to greater than 1, so that even unknown pragmas in
system headers will be warned about. */
@@ -436,7 +450,7 @@ c_common_handle_option (size_t scode, const char *arg, int value,
case OPT_ffreestanding:
value = !value;
- /* Fall through.... */
+ /* Fall through. */
case OPT_fhosted:
flag_hosted = value;
flag_no_builtin = !value;
@@ -610,31 +624,19 @@ c_common_handle_option (size_t scode, const char *arg, int value,
case OPT_std_c__11:
case OPT_std_gnu__11:
if (!preprocessing_asm_p)
- {
- set_std_cxx11 (code == OPT_std_c__11 /* ISO */);
- if (code == OPT_std_c__11)
- cpp_opts->ext_numeric_literals = 0;
- }
+ set_std_cxx11 (code == OPT_std_c__11 /* ISO */);
break;
case OPT_std_c__14:
case OPT_std_gnu__14:
if (!preprocessing_asm_p)
- {
- set_std_cxx14 (code == OPT_std_c__14 /* ISO */);
- if (code == OPT_std_c__14)
- cpp_opts->ext_numeric_literals = 0;
- }
+ set_std_cxx14 (code == OPT_std_c__14 /* ISO */);
break;
case OPT_std_c__1z:
case OPT_std_gnu__1z:
if (!preprocessing_asm_p)
- {
- set_std_cxx1z (code == OPT_std_c__1z /* ISO */);
- if (code == OPT_std_c__1z)
- cpp_opts->ext_numeric_literals = 0;
- }
+ set_std_cxx1z (code == OPT_std_c__1z /* ISO */);
break;
case OPT_std_c90:
@@ -742,7 +744,12 @@ c_common_post_options (const char **pfilename)
in_fnames[0] = "";
}
else if (strcmp (in_fnames[0], "-") == 0)
- in_fnames[0] = "";
+ {
+ if (pch_file)
+ error ("cannot use %<-%> as input filename for a precompiled header");
+
+ in_fnames[0] = "";
+ }
if (out_fname == NULL || !strcmp (out_fname, "-"))
out_fname = "";
@@ -767,8 +774,7 @@ c_common_post_options (const char **pfilename)
support. */
if (c_dialect_cxx ())
{
- if (flag_excess_precision_cmdline == EXCESS_PRECISION_STANDARD
- && TARGET_FLT_EVAL_METHOD_NON_DEFAULT)
+ if (flag_excess_precision_cmdline == EXCESS_PRECISION_STANDARD)
sorry ("-fexcess-precision=standard for C++");
flag_excess_precision_cmdline = EXCESS_PRECISION_FAST;
}
@@ -787,6 +793,18 @@ c_common_post_options (const char **pfilename)
&& flag_unsafe_math_optimizations == 0)
flag_fp_contract_mode = FP_CONTRACT_OFF;
+ /* If we are compiling C, and we are outside of a standards mode,
+ we can permit the new values from ISO/IEC TS 18661-3 for
+ FLT_EVAL_METHOD. Otherwise, we must restrict the possible values to
+ the set specified in ISO C99/C11. */
+ if (!flag_iso
+ && !c_dialect_cxx ()
+ && (global_options_set.x_flag_permitted_flt_eval_methods
+ == PERMITTED_FLT_EVAL_METHODS_DEFAULT))
+ flag_permitted_flt_eval_methods = PERMITTED_FLT_EVAL_METHODS_TS_18661;
+ else
+ flag_permitted_flt_eval_methods = PERMITTED_FLT_EVAL_METHODS_C11;
+
/* 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)
@@ -868,6 +886,10 @@ c_common_post_options (const char **pfilename)
warn_shift_negative_value = (extra_warnings
&& (cxx_dialect >= cxx11 || flag_isoc99));
+ /* -Wregister is enabled by default in C++17. */
+ if (!global_options_set.x_warn_register)
+ warn_register = cxx_dialect >= cxx1z;
+
/* Declone C++ 'structors if -Os. */
if (flag_declone_ctor_dtor == -1)
flag_declone_ctor_dtor = optimize_size;
@@ -887,15 +909,25 @@ c_common_post_options (const char **pfilename)
}
else if (flag_abi_compat_version == -1)
{
- /* Generate compatibility aliases for ABI v8 (5.1) by default. */
+ /* Generate compatibility aliases for ABI v10 (6.1) by default. */
flag_abi_compat_version
- = (flag_abi_version == 0 ? 8 : 0);
+ = (flag_abi_version == 0 ? 10 : 0);
}
/* Change flag_abi_version to be the actual current ABI level for the
benefit of c_cpp_builtins. */
if (flag_abi_version == 0)
- flag_abi_version = 10;
+ flag_abi_version = 11;
+
+ /* By default, enable the new inheriting constructor semantics along with ABI
+ 11. New and old should coexist fine, but it is a change in what
+ artificial symbols are generated. */
+ if (!global_options_set.x_flag_new_inheriting_ctors)
+ flag_new_inheriting_ctors = abi_version_at_least (11);
+
+ /* For GCC 7, only enable DR150 resolution by default if -std=c++1z. */
+ if (!global_options_set.x_flag_new_ttp)
+ flag_new_ttp = (cxx_dialect >= cxx1z);
if (cxx_dialect >= cxx11)
{
@@ -906,10 +938,21 @@ c_common_post_options (const char **pfilename)
if (warn_narrowing == -1)
warn_narrowing = 1;
+
+ /* Unless -f{,no-}ext-numeric-literals has been used explicitly,
+ for -std=c++{11,14,1z} default to -fno-ext-numeric-literals. */
+ if (flag_iso && !global_options_set.x_flag_ext_numeric_literals)
+ cpp_opts->ext_numeric_literals = 0;
}
else if (warn_narrowing == -1)
warn_narrowing = 0;
+ /* C++17 has stricter evaluation order requirements; let's use some of them
+ for earlier C++ as well, so chaining works as expected. */
+ if (c_dialect_cxx ()
+ && flag_strong_eval_order == -1)
+ flag_strong_eval_order = (cxx_dialect >= cxx1z ? 2 : 1);
+
/* Global sized deallocation is new in C++14. */
if (flag_sized_deallocation == -1)
flag_sized_deallocation = (cxx_dialect >= cxx14);
@@ -1267,6 +1310,11 @@ sanitize_cpp_opts (void)
if (flag_working_directory == -1)
flag_working_directory = (debug_info_level != DINFO_LEVEL_NONE);
+ if (warn_implicit_fallthrough < 5)
+ cpp_opts->cpp_warn_implicit_fallthrough = warn_implicit_fallthrough;
+ else
+ cpp_opts->cpp_warn_implicit_fallthrough = 0;
+
if (cpp_opts->directives_only)
{
if (cpp_warn_unused_macros)
diff --git a/gcc/c-family/c-pch.c b/gcc/c-family/c-pch.c
index 9147c62be5..482078ac55 100644
--- a/gcc/c-family/c-pch.c
+++ b/gcc/c-family/c-pch.c
@@ -1,5 +1,5 @@
/* Precompiled header implementation for the C languages.
- Copyright (C) 2000-2016 Free Software Foundation, Inc.
+ Copyright (C) 2000-2017 Free Software Foundation, Inc.
This file is part of GCC.
diff --git a/gcc/c-family/c-ppoutput.c b/gcc/c-family/c-ppoutput.c
index cc433c9a40..d1c92379f6 100644
--- a/gcc/c-family/c-ppoutput.c
+++ b/gcc/c-family/c-ppoutput.c
@@ -1,5 +1,5 @@
/* Preprocess only, using cpplib.
- Copyright (C) 1995-2016 Free Software Foundation, Inc.
+ Copyright (C) 1995-2017 Free Software Foundation, Inc.
Written by Per Bothner, 1994-95.
This program is free software; you can redistribute it and/or modify it
@@ -150,6 +150,7 @@ init_pp_output (FILE *out_stream)
}
cb->has_attribute = c_common_has_attribute;
+ cb->get_source_date_epoch = cb_get_source_date_epoch;
/* Initialize the print structure. */
print.src_line = 1;
diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c
index c73aa82210..55c2b68865 100644
--- a/gcc/c-family/c-pragma.c
+++ b/gcc/c-family/c-pragma.c
@@ -1,5 +1,5 @@
/* Handle #pragma, system V.4 style. Supports #pragma weak and #pragma pack.
- Copyright (C) 1992-2016 Free Software Foundation, Inc.
+ Copyright (C) 1992-2017 Free Software Foundation, Inc.
This file is part of GCC.
@@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. If not see
#include "target.h"
#include "function.h" /* For cfun. */
#include "c-common.h"
+#include "memmodel.h"
#include "tm_p.h" /* For REGISTER_TARGET_PRAGMAS. */
#include "stringpool.h"
#include "cgraph.h"
@@ -214,6 +215,7 @@ handle_pragma_pack (cpp_reader * ARG_UNUSED (dummy))
align = maximum_field_alignment;
break;
}
+ /* FALLTHRU */
default:
GCC_BAD2 ("alignment must be a small power of two, not %d", align);
}
@@ -891,7 +893,7 @@ handle_pragma_target(cpp_reader *ARG_UNUSED(dummy))
args = nreverse (args);
if (targetm.target_option.pragma_parse (args, NULL_TREE))
- current_target_pragma = args;
+ current_target_pragma = chainon (current_target_pragma, args);
}
}
@@ -1286,7 +1288,7 @@ static const struct omp_pragma_def omp_pragmas[] = {
{ "threadprivate", PRAGMA_OMP_THREADPRIVATE }
};
static const struct omp_pragma_def omp_pragmas_simd[] = {
- { "declare", PRAGMA_OMP_DECLARE_REDUCTION },
+ { "declare", PRAGMA_OMP_DECLARE },
{ "distribute", PRAGMA_OMP_DISTRIBUTE },
{ "for", PRAGMA_OMP_FOR },
{ "parallel", PRAGMA_OMP_PARALLEL },
diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h
index 65f10db6e6..a79036e97e 100644
--- a/gcc/c-family/c-pragma.h
+++ b/gcc/c-family/c-pragma.h
@@ -1,5 +1,5 @@
/* Pragma related interfaces.
- Copyright (C) 1995-2016 Free Software Foundation, Inc.
+ Copyright (C) 1995-2017 Free Software Foundation, Inc.
This file is part of GCC.
@@ -46,7 +46,7 @@ enum pragma_kind {
PRAGMA_OMP_CANCEL,
PRAGMA_OMP_CANCELLATION_POINT,
PRAGMA_OMP_CRITICAL,
- PRAGMA_OMP_DECLARE_REDUCTION,
+ PRAGMA_OMP_DECLARE,
PRAGMA_OMP_DISTRIBUTE,
PRAGMA_OMP_END_DECLARE_TARGET,
PRAGMA_OMP_FLUSH,
diff --git a/gcc/c-family/c-pretty-print.c b/gcc/c-family/c-pretty-print.c
index 704d21daaa..5d79519fa7 100644
--- a/gcc/c-family/c-pretty-print.c
+++ b/gcc/c-family/c-pretty-print.c
@@ -1,5 +1,5 @@
/* Subroutines common to both C and C++ pretty-printers.
- Copyright (C) 2002-2016 Free Software Foundation, Inc.
+ Copyright (C) 2002-2017 Free Software Foundation, Inc.
Contributed by Gabriel Dos Reis <gdr@integrable-solutions.net>
This file is part of GCC.
@@ -344,14 +344,17 @@ c_pretty_printer::simple_type_specifier (tree t)
else
{
int prec = TYPE_PRECISION (t);
+ tree common_t;
if (ALL_FIXED_POINT_MODE_P (TYPE_MODE (t)))
- t = c_common_type_for_mode (TYPE_MODE (t), TYPE_SATURATING (t));
+ common_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))
+ common_t = c_common_type_for_mode (TYPE_MODE (t),
+ TYPE_UNSIGNED (t));
+ if (common_t && TYPE_NAME (common_t))
{
- simple_type_specifier (t);
- if (TYPE_PRECISION (t) != prec)
+ simple_type_specifier (common_t);
+ if (TYPE_PRECISION (common_t) != prec)
{
pp_colon (this);
pp_decimal_int (this, prec);
@@ -901,15 +904,6 @@ pp_c_void_constant (c_pretty_printer *pp)
static void
pp_c_integer_constant (c_pretty_printer *pp, tree i)
{
- int idx;
-
- /* We are going to compare the type of I to other types using
- pointer comparison so we need to use its canonical type. */
- tree type =
- TYPE_CANONICAL (TREE_TYPE (i))
- ? TYPE_CANONICAL (TREE_TYPE (i))
- : TREE_TYPE (i);
-
if (tree_fits_shwi_p (i))
pp_wide_integer (pp, tree_to_shwi (i));
else if (tree_fits_uhwi_p (i))
@@ -926,24 +920,6 @@ pp_c_integer_constant (c_pretty_printer *pp, tree i)
print_hex (wi, pp_buffer (pp)->digit_buffer);
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 for (idx = 0; idx < NUM_INT_N_ENTS; idx ++)
- if (int_n_enabled_p[idx])
- {
- char buf[2+20];
- if (type == int_n_trees[idx].signed_type
- || type == int_n_trees[idx].unsigned_type)
- {
- sprintf (buf, "I%d", int_n_data[idx].bitsize);
- pp_string (pp, buf);
- }
- }
}
/* Print out a CHARACTER literal. */
@@ -1045,6 +1021,16 @@ pp_c_floating_constant (c_pretty_printer *pp, tree r)
pp_string (pp, "dd");
else if (TREE_TYPE (r) == dfloat32_type_node)
pp_string (pp, "df");
+ else if (TREE_TYPE (r) != double_type_node)
+ for (int i = 0; i < NUM_FLOATN_NX_TYPES; i++)
+ if (TREE_TYPE (r) == FLOATN_NX_TYPE_NODE (i))
+ {
+ pp_character (pp, 'f');
+ pp_decimal_int (pp, floatn_nx_types[i].n);
+ if (floatn_nx_types[i].extended)
+ pp_character (pp, 'x');
+ break;
+ }
}
/* Print out a FIXED value as a decimal-floating-constant. */
@@ -1662,7 +1648,7 @@ c_pretty_printer::postfix_expression (tree e)
id_expression (TREE_OPERAND (e, 0));
break;
}
- /* else fall through. */
+ /* fall through. */
default:
primary_expression (e);
@@ -2390,7 +2376,8 @@ pp_c_tree_decl_identifier (c_pretty_printer *pp, tree t)
else
{
static char xname[8];
- sprintf (xname, "<U%4x>", ((unsigned)((uintptr_t)(t) & 0xffff)));
+ sprintf (xname, "<U%4hx>", ((unsigned short) ((uintptr_t) (t)
+ & 0xffff)));
name = xname;
}
diff --git a/gcc/c-family/c-pretty-print.h b/gcc/c-family/c-pretty-print.h
index 253f192239..86a4ae3263 100644
--- a/gcc/c-family/c-pretty-print.h
+++ b/gcc/c-family/c-pretty-print.h
@@ -1,5 +1,5 @@
/* Various declarations for the C and C++ pretty-printers.
- Copyright (C) 2002-2016 Free Software Foundation, Inc.
+ Copyright (C) 2002-2017 Free Software Foundation, Inc.
Contributed by Gabriel Dos Reis <gdr@integrable-solutions.net>
This file is part of GCC.
diff --git a/gcc/c-family/c-semantics.c b/gcc/c-family/c-semantics.c
index 4845a8b54a..3ceb714e4b 100644
--- a/gcc/c-family/c-semantics.c
+++ b/gcc/c-family/c-semantics.c
@@ -1,5 +1,5 @@
/* This file contains subroutine used by the C front-end to construct GENERIC.
- Copyright (C) 2000-2016 Free Software Foundation, Inc.
+ Copyright (C) 2000-2017 Free Software Foundation, Inc.
Written by Benjamin Chelf (chelf@codesourcery.com).
This file is part of GCC.
diff --git a/gcc/c-family/c-target-def.h b/gcc/c-family/c-target-def.h
index d0c03a75b6..781afbc78f 100644
--- a/gcc/c-family/c-target-def.h
+++ b/gcc/c-family/c-target-def.h
@@ -1,5 +1,5 @@
/* Default initializers for C-family target hooks.
- Copyright (C) 2011-2016 Free Software Foundation, Inc.
+ Copyright (C) 2011-2017 Free Software Foundation, Inc.
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
diff --git a/gcc/c-family/c-target.def b/gcc/c-family/c-target.def
index 0083835c1d..8318e50f3a 100644
--- a/gcc/c-family/c-target.def
+++ b/gcc/c-family/c-target.def
@@ -1,5 +1,5 @@
/* Target hook definitions for C-family front ends.
- Copyright (C) 2001-2016 Free Software Foundation, Inc.
+ Copyright (C) 2001-2017 Free Software Foundation, Inc.
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
diff --git a/gcc/c-family/c-target.h b/gcc/c-family/c-target.h
index 1a248a56db..1c8d42a709 100644
--- a/gcc/c-family/c-target.h
+++ b/gcc/c-family/c-target.h
@@ -1,5 +1,5 @@
/* Data structure definitions for target-specific C-family behavior.
- Copyright (C) 2001-2016 Free Software Foundation, Inc.
+ Copyright (C) 2001-2017 Free Software Foundation, Inc.
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
diff --git a/gcc/c-family/c-ubsan.c b/gcc/c-family/c-ubsan.c
index 4022bdf796..e48841a334 100644
--- a/gcc/c-family/c-ubsan.c
+++ b/gcc/c-family/c-ubsan.c
@@ -1,5 +1,5 @@
/* UndefinedBehaviorSanitizer, undefined behavior detector.
- Copyright (C) 2013-2016 Free Software Foundation, Inc.
+ Copyright (C) 2013-2017 Free Software Foundation, Inc.
Contributed by Marek Polacek <polacek@redhat.com>
This file is part of GCC.
@@ -114,6 +114,9 @@ ubsan_instrument_shift (location_t loc, enum tree_code code,
tree t, tt = NULL_TREE;
tree type0 = TREE_TYPE (op0);
tree type1 = TREE_TYPE (op1);
+ if (!INTEGRAL_TYPE_P (type0))
+ return NULL_TREE;
+
tree op1_utype = unsigned_type_for (type1);
HOST_WIDE_INT op0_prec = TYPE_PRECISION (type0);
tree uprecm1 = build_int_cst (op1_utype, op0_prec - 1);
@@ -126,9 +129,9 @@ ubsan_instrument_shift (location_t loc, enum tree_code code,
/* If this is not a signed operation, don't perform overflow checks.
Also punt on bit-fields. */
- if (!INTEGRAL_TYPE_P (type0)
- || TYPE_OVERFLOW_WRAPS (type0)
- || GET_MODE_BITSIZE (TYPE_MODE (type0)) != TYPE_PRECISION (type0))
+ if (TYPE_OVERFLOW_WRAPS (type0)
+ || GET_MODE_BITSIZE (TYPE_MODE (type0)) != TYPE_PRECISION (type0)
+ || (flag_sanitize & SANITIZE_SHIFT_BASE) == 0)
;
/* For signed x << y, in C99/C11, the following:
@@ -169,8 +172,28 @@ ubsan_instrument_shift (location_t loc, enum tree_code code,
/* In case we have a SAVE_EXPR in a conditional context, we need to
make sure it gets evaluated before the condition. */
t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), unshare_expr (op0), t);
- t = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, t,
- tt ? tt : integer_zero_node);
+ t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), unshare_expr (op1), t);
+
+ enum sanitize_code recover_kind = SANITIZE_SHIFT_EXPONENT;
+ tree else_t = void_node;
+ if (tt)
+ {
+ if ((flag_sanitize & SANITIZE_SHIFT_EXPONENT) == 0)
+ {
+ t = fold_build1 (TRUTH_NOT_EXPR, boolean_type_node, t);
+ t = fold_build2 (TRUTH_AND_EXPR, boolean_type_node, t, tt);
+ recover_kind = SANITIZE_SHIFT_BASE;
+ }
+ else
+ {
+ if (flag_sanitize_undefined_trap_on_error
+ || ((!(flag_sanitize_recover & SANITIZE_SHIFT_EXPONENT))
+ == (!(flag_sanitize_recover & SANITIZE_SHIFT_BASE))))
+ t = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, t, tt);
+ else
+ else_t = tt;
+ }
+ }
if (flag_sanitize_undefined_trap_on_error)
tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
@@ -183,7 +206,7 @@ ubsan_instrument_shift (location_t loc, enum tree_code code,
data = build_fold_addr_expr_loc (loc, data);
enum built_in_function bcode
- = (flag_sanitize_recover & SANITIZE_SHIFT)
+ = (flag_sanitize_recover & recover_kind)
? BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS
: BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS_ABORT;
tt = builtin_decl_explicit (bcode);
@@ -191,8 +214,22 @@ ubsan_instrument_shift (location_t loc, enum tree_code code,
op1 = unshare_expr (op1);
tt = build_call_expr_loc (loc, tt, 3, data, ubsan_encode_value (op0),
ubsan_encode_value (op1));
+ if (else_t != void_node)
+ {
+ bcode = (flag_sanitize_recover & SANITIZE_SHIFT_BASE)
+ ? BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS
+ : BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS_ABORT;
+ tree else_tt = builtin_decl_explicit (bcode);
+ op0 = unshare_expr (op0);
+ op1 = unshare_expr (op1);
+ else_tt = build_call_expr_loc (loc, else_tt, 3, data,
+ ubsan_encode_value (op0),
+ ubsan_encode_value (op1));
+ else_t = fold_build3 (COND_EXPR, void_type_node, else_t,
+ else_tt, void_node);
+ }
}
- t = fold_build3 (COND_EXPR, void_type_node, t, tt, void_node);
+ t = fold_build3 (COND_EXPR, void_type_node, t, tt, else_t);
return t;
}
@@ -233,9 +270,6 @@ ubsan_instrument_return (location_t loc)
{
if (flag_sanitize_undefined_trap_on_error)
return build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
- /* It is possible that PCH zapped table with definitions of sanitizer
- builtins. Reinitialize them if needed. */
- initialize_sanitizer_builtins ();
tree data = ubsan_create_data ("__ubsan_missing_return_data", 1, &loc,
NULL_TREE, NULL_TREE);
@@ -425,17 +459,26 @@ ubsan_maybe_instrument_reference_or_call (location_t loc, tree op, tree ptype,
return fold_build2 (COMPOUND_EXPR, TREE_TYPE (op), call, op);
}
-/* Instrument a NOP_EXPR to REFERENCE_TYPE if needed. */
+/* Instrument a NOP_EXPR to REFERENCE_TYPE or INTEGER_CST with REFERENCE_TYPE
+ type if needed. */
void
-ubsan_maybe_instrument_reference (tree stmt)
+ubsan_maybe_instrument_reference (tree *stmt_p)
{
- tree op = TREE_OPERAND (stmt, 0);
+ tree stmt = *stmt_p;
+ tree op = stmt;
+ if (TREE_CODE (stmt) == NOP_EXPR)
+ op = TREE_OPERAND (stmt, 0);
op = ubsan_maybe_instrument_reference_or_call (EXPR_LOCATION (stmt), op,
TREE_TYPE (stmt),
UBSAN_REF_BINDING);
if (op)
- TREE_OPERAND (stmt, 0) = op;
+ {
+ if (TREE_CODE (stmt) == NOP_EXPR)
+ TREE_OPERAND (stmt, 0) = op;
+ else
+ *stmt_p = op;
+ }
}
/* Instrument a CALL_EXPR to a method if needed. */
diff --git a/gcc/c-family/c-ubsan.h b/gcc/c-family/c-ubsan.h
index 30d4f971a7..3c3ffc7f7a 100644
--- a/gcc/c-family/c-ubsan.h
+++ b/gcc/c-family/c-ubsan.h
@@ -1,5 +1,5 @@
/* UndefinedBehaviorSanitizer, undefined behavior detector.
- Copyright (C) 2013-2016 Free Software Foundation, Inc.
+ Copyright (C) 2013-2017 Free Software Foundation, Inc.
Contributed by Marek Polacek <polacek@redhat.com>
This file is part of GCC.
@@ -28,7 +28,7 @@ extern tree ubsan_instrument_return (location_t);
extern tree ubsan_instrument_bounds (location_t, tree, tree *, bool);
extern bool ubsan_array_ref_instrumented_p (const_tree);
extern void ubsan_maybe_instrument_array_ref (tree *, bool);
-extern void ubsan_maybe_instrument_reference (tree);
+extern void ubsan_maybe_instrument_reference (tree *);
extern void ubsan_maybe_instrument_member_call (tree, bool);
/* Declare this here as well as in ubsan.h. */
diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
new file mode 100644
index 0000000000..45dd583111
--- /dev/null
+++ b/gcc/c-family/c-warn.c
@@ -0,0 +1,2286 @@
+/* Diagnostic routines shared by all languages that are variants of C.
+ Copyright (C) 1992-2017 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 "target.h"
+#include "function.h"
+#include "tree.h"
+#include "c-common.h"
+#include "memmodel.h"
+#include "tm_p.h"
+#include "diagnostic.h"
+#include "intl.h"
+#include "asan.h"
+#include "gcc-rich-location.h"
+
+/* 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;
+
+ /* We don't want to warn if either operand comes from a macro
+ expansion. ??? This doesn't work with e.g. NEGATE_EXPR yet;
+ see PR61534. */
+ if (from_macro_expansion_at (EXPR_LOCATION (op_left))
+ || from_macro_expansion_at (EXPR_LOCATION (op_right)))
+ 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 (TREE_CODE (op_right) == CONST_DECL)
+ /* An enumerator counts as a constant. */
+ op_right = DECL_INITIAL (op_right);
+ 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 (fold_for_warn (op_left))
+ || CONSTANT_CLASS_P (fold_for_warn (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;
+
+ /* The range computations only work with scalars. */
+ if (VECTOR_TYPE_P (TREE_TYPE (op_left))
+ || VECTOR_TYPE_P (TREE_TYPE (op_right)))
+ return;
+
+ /* We first test whether either side separately is trivially true
+ (with OR) or trivially false (with AND). If so, do not warn.
+ This is a common idiom for testing ranges of data types in
+ portable code. */
+ lhs = make_range (op_left, &in0_p, &low0, &high0, &strict_overflow_p);
+ if (!lhs)
+ return;
+ if (TREE_CODE (lhs) == C_MAYBE_CONST_EXPR)
+ lhs = C_MAYBE_CONST_EXPR_EXPR (lhs);
+
+ /* If this is an OR operation, invert both sides; now, the result
+ should be always false to get a warning. */
+ if (or_op)
+ in0_p = !in0_p;
+
+ tem = build_range_check (UNKNOWN_LOCATION, type, lhs, in0_p, low0, high0);
+ if (tem && integer_zerop (tem))
+ return;
+
+ rhs = make_range (op_right, &in1_p, &low1, &high1, &strict_overflow_p);
+ if (!rhs)
+ return;
+ if (TREE_CODE (rhs) == C_MAYBE_CONST_EXPR)
+ rhs = C_MAYBE_CONST_EXPR_EXPR (rhs);
+
+ /* If this is an OR operation, invert both sides; now, the result
+ should be always false to get a warning. */
+ if (or_op)
+ in1_p = !in1_p;
+
+ tem = build_range_check (UNKNOWN_LOCATION, type, rhs, in1_p, low1, high1);
+ if (tem && integer_zerop (tem))
+ return;
+
+ /* If both expressions have the same operand, if we can merge the
+ ranges, ... */
+ if (operand_equal_p (lhs, rhs, 0)
+ && merge_ranges (&in_p, &low, &high, in0_p, low0, high0,
+ in1_p, low1, high1))
+ {
+ tem = build_range_check (UNKNOWN_LOCATION, type, lhs, in_p, low, high);
+ /* ... and if the range test is always false, then warn. */
+ if (tem && integer_zerop (tem))
+ {
+ 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");
+ }
+ /* Or warn if the operands have exactly the same range, e.g.
+ A > 0 && A > 0. */
+ else if (tree_int_cst_equal (low0, low1)
+ && tree_int_cst_equal (high0, high1))
+ {
+ if (or_op)
+ warning_at (location, OPT_Wlogical_op,
+ "logical %<or%> of equal expressions");
+ else
+ warning_at (location, OPT_Wlogical_op,
+ "logical %<and%> of equal expressions");
+ }
+ }
+}
+
+/* Helper function for warn_tautological_cmp. Look for ARRAY_REFs
+ with constant indices. */
+
+static tree
+find_array_ref_with_const_idx_r (tree *expr_p, int *, void *)
+{
+ tree expr = *expr_p;
+
+ if ((TREE_CODE (expr) == ARRAY_REF
+ || TREE_CODE (expr) == ARRAY_RANGE_REF)
+ && TREE_CODE (TREE_OPERAND (expr, 1)) == INTEGER_CST)
+ return integer_type_node;
+
+ return NULL_TREE;
+}
+
+/* Warn if a self-comparison always evaluates to true or false. LOC
+ is the location of the comparison with code CODE, LHS and RHS are
+ operands of the comparison. */
+
+void
+warn_tautological_cmp (location_t loc, enum tree_code code, tree lhs, tree rhs)
+{
+ if (TREE_CODE_CLASS (code) != tcc_comparison)
+ return;
+
+ /* Don't warn for various macro expansions. */
+ if (from_macro_expansion_at (loc)
+ || from_macro_expansion_at (EXPR_LOCATION (lhs))
+ || from_macro_expansion_at (EXPR_LOCATION (rhs)))
+ return;
+
+ /* We do not warn for constants because they are typical of macro
+ expansions that test for features, sizeof, and similar. */
+ if (CONSTANT_CLASS_P (fold_for_warn (lhs))
+ || CONSTANT_CLASS_P (fold_for_warn (rhs)))
+ return;
+
+ /* Don't warn for e.g.
+ HOST_WIDE_INT n;
+ ...
+ if (n == (long) n) ...
+ */
+ if ((CONVERT_EXPR_P (lhs) || TREE_CODE (lhs) == NON_LVALUE_EXPR)
+ || (CONVERT_EXPR_P (rhs) || TREE_CODE (rhs) == NON_LVALUE_EXPR))
+ return;
+
+ /* Don't warn if either LHS or RHS has an IEEE floating-point type.
+ It could be a NaN, and NaN never compares equal to anything, even
+ itself. */
+ if (FLOAT_TYPE_P (TREE_TYPE (lhs)) || FLOAT_TYPE_P (TREE_TYPE (rhs)))
+ return;
+
+ if (operand_equal_p (lhs, rhs, 0))
+ {
+ /* Don't warn about array references with constant indices;
+ these are likely to come from a macro. */
+ if (walk_tree_without_duplicates (&lhs, find_array_ref_with_const_idx_r,
+ NULL))
+ return;
+ const bool always_true = (code == EQ_EXPR || code == LE_EXPR
+ || code == GE_EXPR || code == UNLE_EXPR
+ || code == UNGE_EXPR || code == UNEQ_EXPR);
+ if (always_true)
+ warning_at (loc, OPT_Wtautological_compare,
+ "self-comparison always evaluates to true");
+ else
+ warning_at (loc, OPT_Wtautological_compare,
+ "self-comparison always evaluates to false");
+ }
+}
+
+/* Return true iff EXPR only contains boolean operands, or comparisons. */
+
+static bool
+expr_has_boolean_operands_p (tree expr)
+{
+ STRIP_NOPS (expr);
+
+ if (CONVERT_EXPR_P (expr))
+ return bool_promoted_to_int_p (expr);
+ else if (UNARY_CLASS_P (expr))
+ return expr_has_boolean_operands_p (TREE_OPERAND (expr, 0));
+ else if (BINARY_CLASS_P (expr))
+ return (expr_has_boolean_operands_p (TREE_OPERAND (expr, 0))
+ && expr_has_boolean_operands_p (TREE_OPERAND (expr, 1)));
+ else if (COMPARISON_CLASS_P (expr))
+ return true;
+ else
+ return false;
+}
+
+/* Warn about logical not used on the left hand side operand of a comparison.
+ This function assumes that the LHS is inside of TRUTH_NOT_EXPR.
+ Do not warn if RHS is of a boolean type, a logical operator, or
+ a comparison. */
+
+void
+warn_logical_not_parentheses (location_t location, enum tree_code code,
+ tree lhs, tree rhs)
+{
+ if (TREE_CODE_CLASS (code) != tcc_comparison
+ || TREE_TYPE (rhs) == NULL_TREE
+ || TREE_CODE (TREE_TYPE (rhs)) == BOOLEAN_TYPE
+ || truth_value_p (TREE_CODE (rhs)))
+ return;
+
+ /* Don't warn for expression like !x == ~(bool1 | bool2). */
+ if (expr_has_boolean_operands_p (rhs))
+ return;
+
+ /* Don't warn for !x == 0 or !y != 0, those are equivalent to
+ !(x == 0) or !(y != 0). */
+ if ((code == EQ_EXPR || code == NE_EXPR)
+ && integer_zerop (rhs))
+ return;
+
+ if (warning_at (location, OPT_Wlogical_not_parentheses,
+ "logical not is only applied to the left hand side of "
+ "comparison")
+ && EXPR_HAS_LOCATION (lhs))
+ {
+ location_t lhs_loc = EXPR_LOCATION (lhs);
+ rich_location richloc (line_table, lhs_loc);
+ richloc.add_fixit_insert_before (lhs_loc, "(");
+ richloc.add_fixit_insert_after (lhs_loc, ")");
+ inform_at_rich_loc (&richloc, "add parentheses around left hand side "
+ "expression to silence this warning");
+ }
+}
+
+/* Warn if EXP contains any computations whose results are not used.
+ Return true if a warning is printed; false otherwise. LOCUS is the
+ (potential) location of the expression. */
+
+bool
+warn_if_unused_value (const_tree exp, location_t locus)
+{
+ restart:
+ if (TREE_USED (exp) || TREE_NO_WARNING (exp))
+ return false;
+
+ /* Don't warn about void constructs. This includes casting to void,
+ void function calls, and statement expressions with a final cast
+ to void. */
+ if (VOID_TYPE_P (TREE_TYPE (exp)))
+ return false;
+
+ if (EXPR_HAS_LOCATION (exp))
+ locus = EXPR_LOCATION (exp);
+
+ switch (TREE_CODE (exp))
+ {
+ case PREINCREMENT_EXPR:
+ case POSTINCREMENT_EXPR:
+ case PREDECREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
+ case MODIFY_EXPR:
+ case INIT_EXPR:
+ case TARGET_EXPR:
+ case CALL_EXPR:
+ case TRY_CATCH_EXPR:
+ case WITH_CLEANUP_EXPR:
+ case EXIT_EXPR:
+ case VA_ARG_EXPR:
+ return false;
+
+ case BIND_EXPR:
+ /* For a binding, warn if no side effect within it. */
+ exp = BIND_EXPR_BODY (exp);
+ goto restart;
+
+ case SAVE_EXPR:
+ case NON_LVALUE_EXPR:
+ case NOP_EXPR:
+ exp = TREE_OPERAND (exp, 0);
+ goto restart;
+
+ case TRUTH_ORIF_EXPR:
+ case TRUTH_ANDIF_EXPR:
+ /* In && or ||, warn if 2nd operand has no side effect. */
+ exp = TREE_OPERAND (exp, 1);
+ goto restart;
+
+ case COMPOUND_EXPR:
+ if (warn_if_unused_value (TREE_OPERAND (exp, 0), locus))
+ return true;
+ /* Let people do `(foo (), 0)' without a warning. */
+ if (TREE_CONSTANT (TREE_OPERAND (exp, 1)))
+ return false;
+ exp = TREE_OPERAND (exp, 1);
+ goto restart;
+
+ case COND_EXPR:
+ /* If this is an expression with side effects, don't warn; this
+ case commonly appears in macro expansions. */
+ if (TREE_SIDE_EFFECTS (exp))
+ return false;
+ goto warn;
+
+ case INDIRECT_REF:
+ /* Don't warn about automatic dereferencing of references, since
+ the user cannot control it. */
+ if (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == REFERENCE_TYPE)
+ {
+ exp = TREE_OPERAND (exp, 0);
+ goto restart;
+ }
+ /* Fall through. */
+
+ default:
+ /* Referencing a volatile value is a side effect, so don't warn. */
+ if ((DECL_P (exp) || REFERENCE_CLASS_P (exp))
+ && TREE_THIS_VOLATILE (exp))
+ return false;
+
+ /* If this is an expression which has no operands, there is no value
+ to be unused. There are no such language-independent codes,
+ but front ends may define such. */
+ if (EXPRESSION_CLASS_P (exp) && TREE_OPERAND_LENGTH (exp) == 0)
+ return false;
+
+ warn:
+ return warning_at (locus, OPT_Wunused_value, "value computed is not used");
+ }
+}
+
+/* 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_set_subset_of (set2, set1)
+ && !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 about memset (&a, 0, sizeof (&a)); and similar mistakes with
+ sizeof as last operand of certain builtins. */
+
+void
+sizeof_pointer_memaccess_warning (location_t *sizeof_arg_loc, tree callee,
+ vec<tree, va_gc> *params, tree *sizeof_arg,
+ bool (*comp_types) (tree, tree))
+{
+ tree type, dest = NULL_TREE, src = NULL_TREE, tem;
+ bool strop = false, cmp = false;
+ unsigned int idx = ~0;
+ location_t loc;
+
+ if (TREE_CODE (callee) != FUNCTION_DECL
+ || DECL_BUILT_IN_CLASS (callee) != BUILT_IN_NORMAL
+ || vec_safe_length (params) <= 1)
+ return;
+
+ switch (DECL_FUNCTION_CODE (callee))
+ {
+ case BUILT_IN_STRNCMP:
+ case BUILT_IN_STRNCASECMP:
+ cmp = true;
+ /* FALLTHRU */
+ case BUILT_IN_STRNCPY:
+ case BUILT_IN_STRNCPY_CHK:
+ case BUILT_IN_STRNCAT:
+ case BUILT_IN_STRNCAT_CHK:
+ case BUILT_IN_STPNCPY:
+ case BUILT_IN_STPNCPY_CHK:
+ strop = true;
+ /* FALLTHRU */
+ case BUILT_IN_MEMCPY:
+ case BUILT_IN_MEMCPY_CHK:
+ case BUILT_IN_MEMMOVE:
+ case BUILT_IN_MEMMOVE_CHK:
+ if (params->length () < 3)
+ return;
+ src = (*params)[1];
+ dest = (*params)[0];
+ idx = 2;
+ break;
+ case BUILT_IN_BCOPY:
+ if (params->length () < 3)
+ return;
+ src = (*params)[0];
+ dest = (*params)[1];
+ idx = 2;
+ break;
+ case BUILT_IN_MEMCMP:
+ case BUILT_IN_BCMP:
+ if (params->length () < 3)
+ return;
+ src = (*params)[1];
+ dest = (*params)[0];
+ idx = 2;
+ cmp = true;
+ break;
+ case BUILT_IN_MEMSET:
+ case BUILT_IN_MEMSET_CHK:
+ if (params->length () < 3)
+ return;
+ dest = (*params)[0];
+ idx = 2;
+ break;
+ case BUILT_IN_BZERO:
+ dest = (*params)[0];
+ idx = 1;
+ break;
+ case BUILT_IN_STRNDUP:
+ src = (*params)[0];
+ strop = true;
+ idx = 1;
+ break;
+ case BUILT_IN_MEMCHR:
+ if (params->length () < 3)
+ return;
+ src = (*params)[0];
+ idx = 2;
+ break;
+ case BUILT_IN_SNPRINTF:
+ case BUILT_IN_SNPRINTF_CHK:
+ case BUILT_IN_VSNPRINTF:
+ case BUILT_IN_VSNPRINTF_CHK:
+ dest = (*params)[0];
+ idx = 1;
+ strop = true;
+ break;
+ default:
+ break;
+ }
+
+ if (idx >= 3)
+ return;
+
+ if (sizeof_arg[idx] == NULL || sizeof_arg[idx] == error_mark_node)
+ return;
+
+ type = TYPE_P (sizeof_arg[idx])
+ ? sizeof_arg[idx] : TREE_TYPE (sizeof_arg[idx]);
+ if (!POINTER_TYPE_P (type))
+ return;
+
+ if (dest
+ && (tem = tree_strip_nop_conversions (dest))
+ && POINTER_TYPE_P (TREE_TYPE (tem))
+ && comp_types (TREE_TYPE (TREE_TYPE (tem)), type))
+ return;
+
+ if (src
+ && (tem = tree_strip_nop_conversions (src))
+ && POINTER_TYPE_P (TREE_TYPE (tem))
+ && comp_types (TREE_TYPE (TREE_TYPE (tem)), type))
+ return;
+
+ loc = sizeof_arg_loc[idx];
+
+ if (dest && !cmp)
+ {
+ if (!TYPE_P (sizeof_arg[idx])
+ && operand_equal_p (dest, sizeof_arg[idx], 0)
+ && comp_types (TREE_TYPE (dest), type))
+ {
+ if (TREE_CODE (sizeof_arg[idx]) == ADDR_EXPR && !strop)
+ warning_at (loc, OPT_Wsizeof_pointer_memaccess,
+ "argument to %<sizeof%> in %qD call is the same "
+ "expression as the destination; did you mean to "
+ "remove the addressof?", callee);
+ else if ((TYPE_PRECISION (TREE_TYPE (type))
+ == TYPE_PRECISION (char_type_node))
+ || strop)
+ warning_at (loc, OPT_Wsizeof_pointer_memaccess,
+ "argument to %<sizeof%> in %qD call is the same "
+ "expression as the destination; did you mean to "
+ "provide an explicit length?", callee);
+ else
+ warning_at (loc, OPT_Wsizeof_pointer_memaccess,
+ "argument to %<sizeof%> in %qD call is the same "
+ "expression as the destination; did you mean to "
+ "dereference it?", callee);
+ return;
+ }
+
+ if (POINTER_TYPE_P (TREE_TYPE (dest))
+ && !strop
+ && comp_types (TREE_TYPE (dest), type)
+ && !VOID_TYPE_P (TREE_TYPE (type)))
+ {
+ warning_at (loc, OPT_Wsizeof_pointer_memaccess,
+ "argument to %<sizeof%> in %qD call is the same "
+ "pointer type %qT as the destination; expected %qT "
+ "or an explicit length", callee, TREE_TYPE (dest),
+ TREE_TYPE (TREE_TYPE (dest)));
+ return;
+ }
+ }
+
+ if (src && !cmp)
+ {
+ if (!TYPE_P (sizeof_arg[idx])
+ && operand_equal_p (src, sizeof_arg[idx], 0)
+ && comp_types (TREE_TYPE (src), type))
+ {
+ if (TREE_CODE (sizeof_arg[idx]) == ADDR_EXPR && !strop)
+ warning_at (loc, OPT_Wsizeof_pointer_memaccess,
+ "argument to %<sizeof%> in %qD call is the same "
+ "expression as the source; did you mean to "
+ "remove the addressof?", callee);
+ else if ((TYPE_PRECISION (TREE_TYPE (type))
+ == TYPE_PRECISION (char_type_node))
+ || strop)
+ warning_at (loc, OPT_Wsizeof_pointer_memaccess,
+ "argument to %<sizeof%> in %qD call is the same "
+ "expression as the source; did you mean to "
+ "provide an explicit length?", callee);
+ else
+ warning_at (loc, OPT_Wsizeof_pointer_memaccess,
+ "argument to %<sizeof%> in %qD call is the same "
+ "expression as the source; did you mean to "
+ "dereference it?", callee);
+ return;
+ }
+
+ if (POINTER_TYPE_P (TREE_TYPE (src))
+ && !strop
+ && comp_types (TREE_TYPE (src), type)
+ && !VOID_TYPE_P (TREE_TYPE (type)))
+ {
+ warning_at (loc, OPT_Wsizeof_pointer_memaccess,
+ "argument to %<sizeof%> in %qD call is the same "
+ "pointer type %qT as the source; expected %qT "
+ "or an explicit length", callee, TREE_TYPE (src),
+ TREE_TYPE (TREE_TYPE (src)));
+ return;
+ }
+ }
+
+ if (dest)
+ {
+ if (!TYPE_P (sizeof_arg[idx])
+ && operand_equal_p (dest, sizeof_arg[idx], 0)
+ && comp_types (TREE_TYPE (dest), type))
+ {
+ if (TREE_CODE (sizeof_arg[idx]) == ADDR_EXPR && !strop)
+ warning_at (loc, OPT_Wsizeof_pointer_memaccess,
+ "argument to %<sizeof%> in %qD call is the same "
+ "expression as the first source; did you mean to "
+ "remove the addressof?", callee);
+ else if ((TYPE_PRECISION (TREE_TYPE (type))
+ == TYPE_PRECISION (char_type_node))
+ || strop)
+ warning_at (loc, OPT_Wsizeof_pointer_memaccess,
+ "argument to %<sizeof%> in %qD call is the same "
+ "expression as the first source; did you mean to "
+ "provide an explicit length?", callee);
+ else
+ warning_at (loc, OPT_Wsizeof_pointer_memaccess,
+ "argument to %<sizeof%> in %qD call is the same "
+ "expression as the first source; did you mean to "
+ "dereference it?", callee);
+ return;
+ }
+
+ if (POINTER_TYPE_P (TREE_TYPE (dest))
+ && !strop
+ && comp_types (TREE_TYPE (dest), type)
+ && !VOID_TYPE_P (TREE_TYPE (type)))
+ {
+ warning_at (loc, OPT_Wsizeof_pointer_memaccess,
+ "argument to %<sizeof%> in %qD call is the same "
+ "pointer type %qT as the first source; expected %qT "
+ "or an explicit length", callee, TREE_TYPE (dest),
+ TREE_TYPE (TREE_TYPE (dest)));
+ return;
+ }
+ }
+
+ if (src)
+ {
+ if (!TYPE_P (sizeof_arg[idx])
+ && operand_equal_p (src, sizeof_arg[idx], 0)
+ && comp_types (TREE_TYPE (src), type))
+ {
+ if (TREE_CODE (sizeof_arg[idx]) == ADDR_EXPR && !strop)
+ warning_at (loc, OPT_Wsizeof_pointer_memaccess,
+ "argument to %<sizeof%> in %qD call is the same "
+ "expression as the second source; did you mean to "
+ "remove the addressof?", callee);
+ else if ((TYPE_PRECISION (TREE_TYPE (type))
+ == TYPE_PRECISION (char_type_node))
+ || strop)
+ warning_at (loc, OPT_Wsizeof_pointer_memaccess,
+ "argument to %<sizeof%> in %qD call is the same "
+ "expression as the second source; did you mean to "
+ "provide an explicit length?", callee);
+ else
+ warning_at (loc, OPT_Wsizeof_pointer_memaccess,
+ "argument to %<sizeof%> in %qD call is the same "
+ "expression as the second source; did you mean to "
+ "dereference it?", callee);
+ return;
+ }
+
+ if (POINTER_TYPE_P (TREE_TYPE (src))
+ && !strop
+ && comp_types (TREE_TYPE (src), type)
+ && !VOID_TYPE_P (TREE_TYPE (type)))
+ {
+ warning_at (loc, OPT_Wsizeof_pointer_memaccess,
+ "argument to %<sizeof%> in %qD call is the same "
+ "pointer type %qT as the second source; expected %qT "
+ "or an explicit length", callee, TREE_TYPE (src),
+ TREE_TYPE (TREE_TYPE (src)));
+ return;
+ }
+ }
+
+}
+
+/* Warn for unlikely, improbable, or stupid DECL declarations
+ of `main'. */
+
+void
+check_main_parameter_types (tree decl)
+{
+ function_args_iterator iter;
+ tree type;
+ int argct = 0;
+
+ FOREACH_FUNCTION_ARGS (TREE_TYPE (decl), type, iter)
+ {
+ /* XXX void_type_node belies the abstraction. */
+ if (type == void_type_node || type == error_mark_node)
+ break;
+
+ tree t = type;
+ if (TYPE_ATOMIC (t))
+ pedwarn (input_location, OPT_Wmain,
+ "%<_Atomic%>-qualified parameter type %qT of %q+D",
+ type, decl);
+ while (POINTER_TYPE_P (t))
+ {
+ t = TREE_TYPE (t);
+ if (TYPE_ATOMIC (t))
+ pedwarn (input_location, OPT_Wmain,
+ "%<_Atomic%>-qualified parameter type %qT of %q+D",
+ type, decl);
+ }
+
+ ++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);
+
+ if (stdarg_p (TREE_TYPE (decl)))
+ pedwarn (input_location, OPT_Wmain,
+ "%q+D declared as variadic function", decl);
+}
+
+/* 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 (location_t loc, tree type, tree expr)
+{
+ tree expr_type = TREE_TYPE (expr);
+ enum conversion_safety conversion_kind;
+
+ if (!warn_conversion && !warn_sign_conversion && !warn_float_conversion)
+ return;
+
+ /* This may happen, because for LHS op= RHS we preevaluate
+ RHS and create C_MAYBE_CONST_EXPR <SAVE_EXPR <RHS>>, which
+ means we could no longer see the code of the EXPR. */
+ if (TREE_CODE (expr) == C_MAYBE_CONST_EXPR)
+ expr = C_MAYBE_CONST_EXPR_EXPR (expr);
+ if (TREE_CODE (expr) == SAVE_EXPR)
+ expr = TREE_OPERAND (expr, 0);
+
+ 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:
+ case COMPLEX_CST:
+ conversion_kind = unsafe_conversion_p (loc, type, expr, true);
+ if (conversion_kind == UNSAFE_REAL)
+ warning_at (loc, OPT_Wfloat_conversion,
+ "conversion to %qT alters %qT constant value",
+ type, expr_type);
+ else if (conversion_kind)
+ warning_at (loc, OPT_Wconversion,
+ "conversion to %qT alters %qT constant value",
+ type, expr_type);
+ return;
+
+ case COND_EXPR:
+ {
+ /* In case of COND_EXPR, 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);
+
+ conversion_warning (loc, type, op1);
+ conversion_warning (loc, type, op2);
+ return;
+ }
+
+ default: /* 'expr' is not a constant. */
+ conversion_kind = unsafe_conversion_p (loc, type, expr, true);
+ if (conversion_kind == UNSAFE_REAL)
+ warning_at (loc, OPT_Wfloat_conversion,
+ "conversion to %qT from %qT may alter its value",
+ type, expr_type);
+ else if (conversion_kind == UNSAFE_IMAGINARY)
+ warning_at (loc, OPT_Wconversion,
+ "conversion to %qT from %qT discards imaginary component",
+ type, expr_type);
+ else if (conversion_kind)
+ 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 (location_t loc, tree type, tree expr,
+ tree result)
+{
+ loc = expansion_point_location_if_in_system_header (loc);
+
+ 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_at (loc, OPT_Woverflow,
+ "large integer implicitly truncated to unsigned type");
+ else
+ conversion_warning (loc, type, expr);
+ }
+ else if (!int_fits_type_p (expr, c_common_unsigned_type (type)))
+ warning_at (loc, 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_at (loc, OPT_Woverflow,
+ "overflow in implicit constant conversion");
+
+ else
+ conversion_warning (loc, type, expr);
+ }
+ else if ((TREE_CODE (result) == INTEGER_CST
+ || TREE_CODE (result) == FIXED_CST) && TREE_OVERFLOW (result))
+ warning_at (loc, OPT_Woverflow,
+ "overflow in implicit constant conversion");
+ else
+ conversion_warning (loc, type, expr);
+}
+
+/* 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[WIDE_INT_PRINT_BUFFER_SIZE];
+
+ if (tree_fits_uhwi_p (key))
+ print_dec (key, buf, UNSIGNED);
+ else if (tree_fits_shwi_p (key))
+ print_dec (key, buf, SIGNED);
+ else
+ print_hex (key, buf);
+
+ 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, bool bool_cond_p,
+ bool outside_range_p)
+{
+ splay_tree_node default_node;
+ splay_tree_node node;
+ tree chain;
+
+ if (!warn_switch && !warn_switch_enum && !warn_switch_default
+ && !warn_switch_bool)
+ 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");
+
+ /* There are certain cases where -Wswitch-bool warnings aren't
+ desirable, such as
+ switch (boolean)
+ {
+ case true: ...
+ case false: ...
+ }
+ so be careful here. */
+ if (warn_switch_bool && bool_cond_p)
+ {
+ splay_tree_node min_node;
+ /* If there's a default node, it's also the value with the minimal
+ key. So look at the penultimate key (if any). */
+ if (default_node)
+ min_node = splay_tree_successor (cases, (splay_tree_key) NULL);
+ else
+ min_node = splay_tree_min (cases);
+ tree min = min_node ? (tree) min_node->key : NULL_TREE;
+
+ splay_tree_node max_node = splay_tree_max (cases);
+ /* This might be a case range, so look at the value with the
+ maximal key and then check CASE_HIGH. */
+ tree max = max_node ? (tree) max_node->value : NULL_TREE;
+ if (max)
+ max = CASE_HIGH (max) ? CASE_HIGH (max) : CASE_LOW (max);
+
+ /* If there's a case value > 1 or < 0, that is outside bool
+ range, warn. */
+ if (outside_range_p
+ || (max && wi::gts_p (max, 1))
+ || (min && wi::lts_p (min, 0))
+ /* And handle the
+ switch (boolean)
+ {
+ case true: ...
+ case false: ...
+ default: ...
+ }
+ case, where we want to warn. */
+ || (default_node
+ && max && wi::eq_p (max, 1)
+ && min && wi::eq_p (min, 0)))
+ warning_at (switch_location, OPT_Wswitch_bool,
+ "switch condition has boolean value");
+ }
+
+ /* From here on, we only care 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);
+}
+
+/* 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)
+{
+ /* In C++ template declarations it can happen that the type is dependent
+ and not yet known, thus TREE_TYPE (cond) == NULL_TREE. */
+ if (truth_value_p (TREE_CODE (cond))
+ || (TREE_TYPE (cond) != NULL_TREE
+ && TREE_CODE (TREE_TYPE (cond)) == BOOLEAN_TYPE))
+ 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 (location_t loc, 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_at (loc, 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_at (loc, 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 (VAR_P (arg))
+ error_at (loc, 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_at (loc, 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_at (loc, 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_at (loc, 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_at (loc, 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_ARROW_STAR:
+ 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 ();
+ }
+}
+
+/* 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 (location_t loc, tree index)
+{
+ if (TYPE_MAIN_VARIANT (TREE_TYPE (index)) == char_type_node
+ && TREE_CODE (index) != INTEGER_CST)
+ warning_at (loc, 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 (location_t loc, 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)
+ warning_at (EXPR_LOC_OR_LOC (arg_left, loc), OPT_Wparentheses,
+ "suggest parentheses around %<+%> inside %<<<%>");
+ else if (code_right == PLUS_EXPR)
+ warning_at (EXPR_LOC_OR_LOC (arg_right, loc), OPT_Wparentheses,
+ "suggest parentheses around %<+%> inside %<<<%>");
+ else if (code_left == MINUS_EXPR)
+ warning_at (EXPR_LOC_OR_LOC (arg_left, loc), OPT_Wparentheses,
+ "suggest parentheses around %<-%> inside %<<<%>");
+ else if (code_right == MINUS_EXPR)
+ warning_at (EXPR_LOC_OR_LOC (arg_right, loc), OPT_Wparentheses,
+ "suggest parentheses around %<-%> inside %<<<%>");
+ return;
+
+ case RSHIFT_EXPR:
+ if (code_left == PLUS_EXPR)
+ warning_at (EXPR_LOC_OR_LOC (arg_left, loc), OPT_Wparentheses,
+ "suggest parentheses around %<+%> inside %<>>%>");
+ else if (code_right == PLUS_EXPR)
+ warning_at (EXPR_LOC_OR_LOC (arg_right, loc), OPT_Wparentheses,
+ "suggest parentheses around %<+%> inside %<>>%>");
+ else if (code_left == MINUS_EXPR)
+ warning_at (EXPR_LOC_OR_LOC (arg_left, loc), OPT_Wparentheses,
+ "suggest parentheses around %<-%> inside %<>>%>");
+ else if (code_right == MINUS_EXPR)
+ warning_at (EXPR_LOC_OR_LOC (arg_right, loc), OPT_Wparentheses,
+ "suggest parentheses around %<-%> inside %<>>%>");
+ return;
+
+ case TRUTH_ORIF_EXPR:
+ if (code_left == TRUTH_ANDIF_EXPR)
+ warning_at (EXPR_LOC_OR_LOC (arg_left, loc), OPT_Wparentheses,
+ "suggest parentheses around %<&&%> within %<||%>");
+ else if (code_right == TRUTH_ANDIF_EXPR)
+ warning_at (EXPR_LOC_OR_LOC (arg_right, loc), 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)
+ warning_at (EXPR_LOC_OR_LOC (arg_left, loc), OPT_Wparentheses,
+ "suggest parentheses around arithmetic in operand of %<|%>");
+ else if (code_right == BIT_AND_EXPR || code_right == BIT_XOR_EXPR
+ || code_right == PLUS_EXPR || code_right == MINUS_EXPR)
+ warning_at (EXPR_LOC_OR_LOC (arg_right, loc), OPT_Wparentheses,
+ "suggest parentheses around arithmetic in operand of %<|%>");
+ /* Check cases like x|y==z */
+ else if (TREE_CODE_CLASS (code_left) == tcc_comparison)
+ warning_at (EXPR_LOC_OR_LOC (arg_left, loc), OPT_Wparentheses,
+ "suggest parentheses around comparison in operand of %<|%>");
+ else if (TREE_CODE_CLASS (code_right) == tcc_comparison)
+ warning_at (EXPR_LOC_OR_LOC (arg_right, loc), 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_at (EXPR_LOC_OR_LOC (arg_left, loc), 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)
+ warning_at (EXPR_LOC_OR_LOC (arg_left, loc), OPT_Wparentheses,
+ "suggest parentheses around arithmetic in operand of %<^%>");
+ else if (code_right == BIT_AND_EXPR
+ || code_right == PLUS_EXPR || code_right == MINUS_EXPR)
+ warning_at (EXPR_LOC_OR_LOC (arg_right, loc), OPT_Wparentheses,
+ "suggest parentheses around arithmetic in operand of %<^%>");
+ /* Check cases like x^y==z */
+ else if (TREE_CODE_CLASS (code_left) == tcc_comparison)
+ warning_at (EXPR_LOC_OR_LOC (arg_left, loc), OPT_Wparentheses,
+ "suggest parentheses around comparison in operand of %<^%>");
+ else if (TREE_CODE_CLASS (code_right) == tcc_comparison)
+ warning_at (EXPR_LOC_OR_LOC (arg_right, loc), OPT_Wparentheses,
+ "suggest parentheses around comparison in operand of %<^%>");
+ return;
+
+ case BIT_AND_EXPR:
+ if (code_left == PLUS_EXPR)
+ warning_at (EXPR_LOC_OR_LOC (arg_left, loc), OPT_Wparentheses,
+ "suggest parentheses around %<+%> in operand of %<&%>");
+ else if (code_right == PLUS_EXPR)
+ warning_at (EXPR_LOC_OR_LOC (arg_right, loc), OPT_Wparentheses,
+ "suggest parentheses around %<+%> in operand of %<&%>");
+ else if (code_left == MINUS_EXPR)
+ warning_at (EXPR_LOC_OR_LOC (arg_left, loc), OPT_Wparentheses,
+ "suggest parentheses around %<-%> in operand of %<&%>");
+ else if (code_right == MINUS_EXPR)
+ warning_at (EXPR_LOC_OR_LOC (arg_right, loc), OPT_Wparentheses,
+ "suggest parentheses around %<-%> in operand of %<&%>");
+ /* Check cases like x&y==z */
+ else if (TREE_CODE_CLASS (code_left) == tcc_comparison)
+ warning_at (EXPR_LOC_OR_LOC (arg_left, loc), OPT_Wparentheses,
+ "suggest parentheses around comparison in operand of %<&%>");
+ else if (TREE_CODE_CLASS (code_right) == tcc_comparison)
+ warning_at (EXPR_LOC_OR_LOC (arg_right, loc), 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_at (EXPR_LOC_OR_LOC (arg_left, loc), OPT_Wparentheses,
+ "suggest parentheses around operand of "
+ "%<!%> or change %<&%> to %<&&%> or %<!%> to %<~%>");
+ return;
+
+ case EQ_EXPR:
+ if (TREE_CODE_CLASS (code_left) == tcc_comparison)
+ warning_at (EXPR_LOC_OR_LOC (arg_left, loc), OPT_Wparentheses,
+ "suggest parentheses around comparison in operand of %<==%>");
+ else if (TREE_CODE_CLASS (code_right) == tcc_comparison)
+ warning_at (EXPR_LOC_OR_LOC (arg_right, loc), OPT_Wparentheses,
+ "suggest parentheses around comparison in operand of %<==%>");
+ return;
+ case NE_EXPR:
+ if (TREE_CODE_CLASS (code_left) == tcc_comparison)
+ warning_at (EXPR_LOC_OR_LOC (arg_left, loc), OPT_Wparentheses,
+ "suggest parentheses around comparison in operand of %<!=%>");
+ else if (TREE_CODE_CLASS (code_right) == tcc_comparison)
+ warning_at (EXPR_LOC_OR_LOC (arg_right, loc), OPT_Wparentheses,
+ "suggest parentheses around comparison in operand of %<!=%>");
+ return;
+
+ default:
+ if (TREE_CODE_CLASS (code) == tcc_comparison)
+ {
+ if (TREE_CODE_CLASS (code_left) == tcc_comparison
+ && code_left != NE_EXPR && code_left != EQ_EXPR
+ && INTEGRAL_TYPE_P (TREE_TYPE (arg_left)))
+ warning_at (EXPR_LOC_OR_LOC (arg_left, loc), OPT_Wparentheses,
+ "comparisons like %<X<=Y<=Z%> do not "
+ "have their mathematical meaning");
+ else if (TREE_CODE_CLASS (code_right) == tcc_comparison
+ && code_right != NE_EXPR && code_right != EQ_EXPR
+ && INTEGRAL_TYPE_P (TREE_TYPE (arg_right)))
+ warning_at (EXPR_LOC_OR_LOC (arg_right, loc), 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);
+ }
+ else if (asan_sanitize_use_after_scope ())
+ {
+ if (asan_used_labels == NULL)
+ asan_used_labels = new hash_set<tree> (16);
+
+ asan_used_labels->add (label);
+ }
+}
+
+/* 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");
+}
+
+/* Warn for patterns where memset appears to be used incorrectly. The
+ warning location should be LOC. ARG0, and ARG2 are the first and
+ last arguments to the call, while LITERAL_ZERO_MASK has a 1 bit for
+ each argument that was a literal zero. */
+
+void
+warn_for_memset (location_t loc, tree arg0, tree arg2,
+ int literal_zero_mask)
+{
+ if (warn_memset_transposed_args
+ && integer_zerop (arg2)
+ && (literal_zero_mask & (1 << 2)) != 0
+ && (literal_zero_mask & (1 << 1)) == 0)
+ warning_at (loc, OPT_Wmemset_transposed_args,
+ "%<memset%> used with constant zero length "
+ "parameter; this could be due to transposed "
+ "parameters");
+
+ if (warn_memset_elt_size && TREE_CODE (arg2) == INTEGER_CST)
+ {
+ STRIP_NOPS (arg0);
+ if (TREE_CODE (arg0) == ADDR_EXPR)
+ arg0 = TREE_OPERAND (arg0, 0);
+ tree type = TREE_TYPE (arg0);
+ if (type != NULL_TREE && TREE_CODE (type) == ARRAY_TYPE)
+ {
+ tree elt_type = TREE_TYPE (type);
+ tree domain = TYPE_DOMAIN (type);
+ if (!integer_onep (TYPE_SIZE_UNIT (elt_type))
+ && domain != NULL_TREE
+ && TYPE_MAXVAL (domain)
+ && TYPE_MINVAL (domain)
+ && integer_zerop (TYPE_MINVAL (domain))
+ && integer_onep (fold_build2 (MINUS_EXPR, domain,
+ arg2,
+ TYPE_MAXVAL (domain))))
+ warning_at (loc, OPT_Wmemset_elt_size,
+ "%<memset%> used with length equal to "
+ "number of elements without multiplication "
+ "by element size");
+ }
+ }
+}
+
+/* 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 = c_common_get_narrower (op0, &unsignedp0);
+ op1 = c_common_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 = c_common_get_narrower (TREE_OPERAND (op0, 0), &unsignedp0);
+ if (TREE_CODE (op1) == BIT_NOT_EXPR)
+ op1 = c_common_get_narrower (TREE_OPERAND (op1, 0), &unsignedp1);
+
+ if (tree_fits_shwi_p (op0) || tree_fits_shwi_p (op1))
+ {
+ tree primop;
+ HOST_WIDE_INT constant, mask;
+ int unsignedp;
+ unsigned int bits;
+
+ if (tree_fits_shwi_p (op0))
+ {
+ primop = op1;
+ unsignedp = unsignedp1;
+ constant = tree_to_shwi (op0);
+ }
+ else
+ {
+ primop = op0;
+ unsignedp = unsignedp0;
+ constant = tree_to_shwi (op1);
+ }
+
+ bits = TYPE_PRECISION (TREE_TYPE (primop));
+ if (bits < TYPE_PRECISION (result_type)
+ && bits < HOST_BITS_PER_LONG && unsignedp)
+ {
+ mask = HOST_WIDE_INT_M1U << bits;
+ if ((mask & constant) != mask)
+ {
+ if (constant == 0)
+ warning_at (location, 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 warning 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 an invalid conversion has occured, don't warn. */
+ if (result_type == error_mark_node)
+ 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);
+}
+
+/* Possibly warn about unused parameters. */
+
+void
+do_warn_unused_parameter (tree fn)
+{
+ tree decl;
+
+ for (decl = DECL_ARGUMENTS (fn);
+ decl; decl = DECL_CHAIN (decl))
+ if (!TREE_USED (decl) && TREE_CODE (decl) == PARM_DECL
+ && DECL_NAME (decl) && !DECL_ARTIFICIAL (decl)
+ && !TREE_NO_WARNING (decl))
+ warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wunused_parameter,
+ "unused parameter %qD", decl);
+}
+
+/* If DECL is a typedef that is declared in the current function,
+ record it for the purpose of -Wunused-local-typedefs. */
+
+void
+record_locally_defined_typedef (tree decl)
+{
+ struct c_language_function *l;
+
+ if (!warn_unused_local_typedefs
+ || cfun == NULL
+ /* if this is not a locally defined typedef then we are not
+ interested. */
+ || !is_typedef_decl (decl)
+ || !decl_function_context (decl))
+ return;
+
+ l = (struct c_language_function *) cfun->language;
+ vec_safe_push (l->local_typedefs, decl);
+}
+
+/* If T is a TYPE_DECL declared locally, mark it as used. */
+
+void
+maybe_record_typedef_use (tree t)
+{
+ if (!is_typedef_decl (t))
+ return;
+
+ TREE_USED (t) = true;
+}
+
+/* Warn if there are some unused locally defined typedefs in the
+ current function. */
+
+void
+maybe_warn_unused_local_typedefs (void)
+{
+ int i;
+ tree decl;
+ /* The number of times we have emitted -Wunused-local-typedefs
+ warnings. If this is different from errorcount, that means some
+ unrelated errors have been issued. In which case, we'll avoid
+ emitting "unused-local-typedefs" warnings. */
+ static int unused_local_typedefs_warn_count;
+ struct c_language_function *l;
+
+ if (cfun == NULL)
+ return;
+
+ if ((l = (struct c_language_function *) cfun->language) == NULL)
+ return;
+
+ if (warn_unused_local_typedefs
+ && errorcount == unused_local_typedefs_warn_count)
+ {
+ FOR_EACH_VEC_SAFE_ELT (l->local_typedefs, i, decl)
+ if (!TREE_USED (decl))
+ warning_at (DECL_SOURCE_LOCATION (decl),
+ OPT_Wunused_local_typedefs,
+ "typedef %qD locally defined but not used", decl);
+ unused_local_typedefs_warn_count = errorcount;
+ }
+
+ vec_free (l->local_typedefs);
+}
+
+/* If we're creating an if-else-if condition chain, first see if we
+ already have this COND in the CHAIN. If so, warn and don't add COND
+ into the vector, otherwise add the COND there. LOC is the location
+ of COND. */
+
+void
+warn_duplicated_cond_add_or_warn (location_t loc, tree cond, vec<tree> **chain)
+{
+ /* No chain has been created yet. Do nothing. */
+ if (*chain == NULL)
+ return;
+
+ if (TREE_SIDE_EFFECTS (cond))
+ {
+ /* Uh-oh! This condition has a side-effect, thus invalidates
+ the whole chain. */
+ delete *chain;
+ *chain = NULL;
+ return;
+ }
+
+ unsigned int ix;
+ tree t;
+ bool found = false;
+ FOR_EACH_VEC_ELT (**chain, ix, t)
+ if (operand_equal_p (cond, t, 0))
+ {
+ if (warning_at (loc, OPT_Wduplicated_cond,
+ "duplicated %<if%> condition"))
+ inform (EXPR_LOCATION (t), "previously used here");
+ found = true;
+ break;
+ }
+
+ if (!found
+ && !CONSTANT_CLASS_P (cond)
+ /* Don't infinitely grow the chain. */
+ && (*chain)->length () < 512)
+ (*chain)->safe_push (cond);
+}
+
+/* Check and possibly warn if two declarations have contradictory
+ attributes, such as always_inline vs. noinline. */
+
+bool
+diagnose_mismatched_attributes (tree olddecl, tree newdecl)
+{
+ bool warned = false;
+
+ tree a1 = lookup_attribute ("optimize", DECL_ATTRIBUTES (olddecl));
+ tree a2 = lookup_attribute ("optimize", DECL_ATTRIBUTES (newdecl));
+ /* An optimization attribute applied on a declaration after the
+ definition is likely not what the user wanted. */
+ if (a2 != NULL_TREE
+ && DECL_SAVED_TREE (olddecl) != NULL_TREE
+ && (a1 == NULL_TREE || !attribute_list_equal (a1, a2)))
+ warned |= warning (OPT_Wattributes,
+ "optimization attribute on %qD follows "
+ "definition but the attribute doesn%'t match",
+ newdecl);
+
+ /* Diagnose inline __attribute__ ((noinline)) which is silly. */
+ if (DECL_DECLARED_INLINE_P (newdecl)
+ && DECL_UNINLINABLE (olddecl)
+ && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl)))
+ warned |= warning (OPT_Wattributes, "inline declaration of %qD follows "
+ "declaration with attribute noinline", newdecl);
+ else if (DECL_DECLARED_INLINE_P (olddecl)
+ && DECL_UNINLINABLE (newdecl)
+ && lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl)))
+ warned |= warning (OPT_Wattributes, "declaration of %q+D with attribute "
+ "noinline follows inline declaration ", newdecl);
+ else if (lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl))
+ && lookup_attribute ("always_inline", DECL_ATTRIBUTES (olddecl)))
+ warned |= warning (OPT_Wattributes, "declaration of %q+D with attribute "
+ "%qs follows declaration with attribute %qs",
+ newdecl, "noinline", "always_inline");
+ else if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (newdecl))
+ && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl)))
+ warned |= warning (OPT_Wattributes, "declaration of %q+D with attribute "
+ "%qs follows declaration with attribute %qs",
+ newdecl, "always_inline", "noinline");
+ else if (lookup_attribute ("cold", DECL_ATTRIBUTES (newdecl))
+ && lookup_attribute ("hot", DECL_ATTRIBUTES (olddecl)))
+ warned |= warning (OPT_Wattributes, "declaration of %q+D with attribute "
+ "%qs follows declaration with attribute %qs",
+ newdecl, "cold", "hot");
+ else if (lookup_attribute ("hot", DECL_ATTRIBUTES (newdecl))
+ && lookup_attribute ("cold", DECL_ATTRIBUTES (olddecl)))
+ warned |= warning (OPT_Wattributes, "declaration of %q+D with attribute "
+ "%qs follows declaration with attribute %qs",
+ newdecl, "hot", "cold");
+ return warned;
+}
+
+/* Warn if signed left shift overflows. We don't warn
+ about left-shifting 1 into the sign bit in C++14; cf.
+ <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3367.html#1457>
+ LOC is a location of the shift; OP0 and OP1 are the operands.
+ Return true if an overflow is detected, false otherwise. */
+
+bool
+maybe_warn_shift_overflow (location_t loc, tree op0, tree op1)
+{
+ if (TREE_CODE (op0) != INTEGER_CST
+ || TREE_CODE (op1) != INTEGER_CST)
+ return false;
+
+ tree type0 = TREE_TYPE (op0);
+ unsigned int prec0 = TYPE_PRECISION (type0);
+
+ /* Left-hand operand must be signed. */
+ if (TYPE_UNSIGNED (type0))
+ return false;
+
+ unsigned int min_prec = (wi::min_precision (op0, SIGNED)
+ + TREE_INT_CST_LOW (op1));
+ /* Handle the case of left-shifting 1 into the sign bit.
+ * However, shifting 1 _out_ of the sign bit, as in
+ * INT_MIN << 1, is considered an overflow.
+ */
+ if (!tree_int_cst_sign_bit(op0) && min_prec == prec0 + 1)
+ {
+ /* Never warn for C++14 onwards. */
+ if (cxx_dialect >= cxx14)
+ return false;
+ /* Otherwise only if -Wshift-overflow=2. But return
+ true to signal an overflow for the sake of integer
+ constant expressions. */
+ if (warn_shift_overflow < 2)
+ return true;
+ }
+
+ bool overflowed = min_prec > prec0;
+ if (overflowed && c_inhibit_evaluation_warnings == 0)
+ warning_at (loc, OPT_Wshift_overflow_,
+ "result of %qE requires %u bits to represent, "
+ "but %qT only has %u bits",
+ build2_loc (loc, LSHIFT_EXPR, type0, op0, op1),
+ min_prec, type0, prec0);
+
+ return overflowed;
+}
+
+/* Warn about boolean expression compared with an integer value different
+ from true/false. Warns also e.g. about "(i1 == i2) == 2".
+ LOC is the location of the comparison, CODE is its code, OP0 and OP1
+ are the operands of the comparison. The caller must ensure that
+ either operand is a boolean expression. */
+
+void
+maybe_warn_bool_compare (location_t loc, enum tree_code code, tree op0,
+ tree op1)
+{
+ if (TREE_CODE_CLASS (code) != tcc_comparison)
+ return;
+
+ tree f, cst;
+ if (f = fold_for_warn (op0),
+ TREE_CODE (f) == INTEGER_CST)
+ cst = op0 = f;
+ else if (f = fold_for_warn (op1),
+ TREE_CODE (f) == INTEGER_CST)
+ cst = op1 = f;
+ else
+ return;
+
+ if (!integer_zerop (cst) && !integer_onep (cst))
+ {
+ int sign = (TREE_CODE (op0) == INTEGER_CST
+ ? tree_int_cst_sgn (cst) : -tree_int_cst_sgn (cst));
+ if (code == EQ_EXPR
+ || ((code == GT_EXPR || code == GE_EXPR) && sign < 0)
+ || ((code == LT_EXPR || code == LE_EXPR) && sign > 0))
+ warning_at (loc, OPT_Wbool_compare, "comparison of constant %qE "
+ "with boolean expression is always false", cst);
+ else
+ warning_at (loc, OPT_Wbool_compare, "comparison of constant %qE "
+ "with boolean expression is always true", cst);
+ }
+ else if (integer_zerop (cst) || integer_onep (cst))
+ {
+ /* If the non-constant operand isn't of a boolean type, we
+ don't want to warn here. */
+ tree noncst = TREE_CODE (op0) == INTEGER_CST ? op1 : op0;
+ /* Handle booleans promoted to integers. */
+ if (bool_promoted_to_int_p (noncst))
+ /* Warn. */;
+ else if (TREE_CODE (TREE_TYPE (noncst)) != BOOLEAN_TYPE
+ && !truth_value_p (TREE_CODE (noncst)))
+ return;
+ /* Do some magic to get the right diagnostics. */
+ bool flag = TREE_CODE (op0) == INTEGER_CST;
+ flag = integer_zerop (cst) ? flag : !flag;
+ if ((code == GE_EXPR && !flag) || (code == LE_EXPR && flag))
+ warning_at (loc, OPT_Wbool_compare, "comparison of constant %qE "
+ "with boolean expression is always true", cst);
+ else if ((code == LT_EXPR && !flag) || (code == GT_EXPR && flag))
+ warning_at (loc, OPT_Wbool_compare, "comparison of constant %qE "
+ "with boolean expression is always false", cst);
+ }
+}
+
+/* Warn if an argument at position param_pos is passed to a
+ restrict-qualified param, and it aliases with another argument. */
+
+void
+warn_for_restrict (unsigned param_pos, tree *argarray, unsigned nargs)
+{
+ tree arg = argarray[param_pos];
+ if (TREE_VISITED (arg) || integer_zerop (arg))
+ return;
+
+ location_t loc = EXPR_LOC_OR_LOC (arg, input_location);
+ gcc_rich_location richloc (loc);
+
+ unsigned i;
+ auto_vec<int, 16> arg_positions;
+
+ for (i = 0; i < nargs; i++)
+ {
+ if (i == param_pos)
+ continue;
+
+ tree current_arg = argarray[i];
+ if (operand_equal_p (arg, current_arg, 0))
+ {
+ TREE_VISITED (current_arg) = 1;
+ arg_positions.safe_push (i + 1);
+ }
+ }
+
+ if (arg_positions.is_empty ())
+ return;
+
+ int pos;
+ FOR_EACH_VEC_ELT (arg_positions, i, pos)
+ {
+ arg = argarray[pos - 1];
+ if (EXPR_HAS_LOCATION (arg))
+ richloc.add_range (EXPR_LOCATION (arg), false);
+ }
+
+ warning_at_rich_loc_n (&richloc, OPT_Wrestrict, arg_positions.length (),
+ "passing argument %i to restrict-qualified parameter"
+ " aliases with argument %Z",
+ "passing argument %i to restrict-qualified parameter"
+ " aliases with arguments %Z",
+ param_pos + 1, arg_positions.address (),
+ arg_positions.length ());
+}
+
+/* Callback function to determine whether an expression TP or one of its
+ subexpressions comes from macro expansion. Used to suppress bogus
+ warnings. */
+
+static tree
+expr_from_macro_expansion_r (tree *tp, int *, void *)
+{
+ if (CAN_HAVE_LOCATION_P (*tp)
+ && from_macro_expansion_at (EXPR_LOCATION (*tp)))
+ return integer_zero_node;
+
+ return NULL_TREE;
+}
+
+/* Possibly warn when an if-else has identical branches. */
+
+static void
+do_warn_duplicated_branches (tree expr)
+{
+ tree thenb = COND_EXPR_THEN (expr);
+ tree elseb = COND_EXPR_ELSE (expr);
+
+ /* Don't bother if there's no else branch. */
+ if (elseb == NULL_TREE)
+ return;
+
+ /* And don't warn for empty statements. */
+ if (TREE_CODE (thenb) == NOP_EXPR
+ && TREE_TYPE (thenb) == void_type_node
+ && TREE_OPERAND (thenb, 0) == size_zero_node)
+ return;
+
+ /* ... or empty branches. */
+ if (TREE_CODE (thenb) == STATEMENT_LIST
+ && STATEMENT_LIST_HEAD (thenb) == NULL)
+ return;
+
+ /* Compute the hash of the then branch. */
+ inchash::hash hstate0 (0);
+ inchash::add_expr (thenb, hstate0);
+ hashval_t h0 = hstate0.end ();
+
+ /* Compute the hash of the else branch. */
+ inchash::hash hstate1 (0);
+ inchash::add_expr (elseb, hstate1);
+ hashval_t h1 = hstate1.end ();
+
+ /* Compare the hashes. */
+ if (h0 == h1
+ && operand_equal_p (thenb, elseb, OEP_LEXICOGRAPHIC)
+ /* Don't warn if any of the branches or their subexpressions comes
+ from a macro. */
+ && !walk_tree_without_duplicates (&thenb, expr_from_macro_expansion_r,
+ NULL)
+ && !walk_tree_without_duplicates (&elseb, expr_from_macro_expansion_r,
+ NULL))
+ warning_at (EXPR_LOCATION (expr), OPT_Wduplicated_branches,
+ "this condition has identical branches");
+}
+
+/* Callback for c_genericize to implement -Wduplicated-branches. */
+
+tree
+do_warn_duplicated_branches_r (tree *tp, int *, void *)
+{
+ if (TREE_CODE (*tp) == COND_EXPR)
+ do_warn_duplicated_branches (*tp);
+ return NULL_TREE;
+}
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 88038a076f..13b930d75d 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -1,5 +1,5 @@
; Options for the C, ObjC, C++ and ObjC++ front ends.
-; Copyright (C) 2003-2016 Free Software Foundation, Inc.
+; Copyright (C) 2003-2017 Free Software Foundation, Inc.
;
; This file is part of GCC.
;
@@ -200,6 +200,10 @@ F
Driver C ObjC C++ ObjC++ Joined Separate MissingArgError(missing path after %qs)
-F <dir> Add <dir> to the end of the main framework include path.
+fgimple
+C Var(flag_gimple) Init(0)
+Enable parsing GIMPLE.
+
H
C ObjC C++ ObjC++
Print the name of header files as they are used.
@@ -271,10 +275,49 @@ Waddress
C ObjC C++ ObjC++ Var(warn_address) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall)
Warn about suspicious uses of memory addresses.
+Enum
+Name(warn_aligned_new_level) Type(int) UnknownError(argument %qs to %<-Waligned-new%> not recognized)
+
+EnumValue
+Enum(warn_aligned_new_level) String(none) Value(0)
+
+EnumValue
+Enum(warn_aligned_new_level) String(global) Value(1)
+
+EnumValue
+Enum(warn_aligned_new_level) String(all) Value(2)
+
+Waligned-new
+C++ ObjC++ Alias(Waligned-new=,global,none)
+Warn about 'new' of type with extended alignment without -faligned-new.
+
+Waligned-new=
+C++ ObjC++ Var(warn_aligned_new) Enum(warn_aligned_new_level) Joined RejectNegative Warning LangEnabledBy(C++ ObjC++,Wall,1,0)
+-Waligned-new=[none|global|all] Warn even if 'new' uses a class member allocation function.
+
Wall
C ObjC C++ ObjC++ Warning
Enable most warning messages.
+Walloca
+C ObjC C++ ObjC++ Var(warn_alloca) Warning
+Warn on any use of alloca.
+
+Walloc-size-larger-than=
+C ObjC C++ ObjC++ Var(warn_alloc_size_limit) Warning Joined
+-Walloc-size-larger-than=<bytes> Warn for calls to allocation functions that
+attempt to allocate objects larger than the specified number of bytes.
+
+Walloc-zero
+C ObjC C++ ObjC++ Var(warn_alloc_zero) Warning
+-Walloc-zero Warn for calls to allocation functions that specify zero bytes.
+
+Walloca-larger-than=
+C ObjC C++ LTO ObjC++ Var(warn_alloca_limit) Warning Joined RejectNegative UInteger
+-Walloca-larger-than=<number> Warn on unbounded uses of
+alloca, and on bounded uses of alloca whose bound can be larger than
+<number> bytes.
+
Warray-bounds
LangEnabledBy(C ObjC C++ ObjC++,Wall)
; in common.opt
@@ -295,10 +338,18 @@ Wbool-compare
C ObjC C++ ObjC++ Var(warn_bool_compare) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall)
Warn about boolean expression compared with an integer value different from true/false.
+Wbool-operation
+C ObjC C++ ObjC++ Var(warn_bool_op) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall)
+Warn about certain operations on boolean expressions.
+
Wframe-address
C ObjC C++ ObjC++ Var(warn_frame_address) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall)
Warn when __builtin_frame_address or __builtin_return_address is used unsafely.
+Wbuiltin-declaration-mismatch
+C ObjC C++ ObjC++ Var(warn_builtin_declaraion_mismatch) Init(1) Warning
+Warn when a built-in function is declared with the wrong signature.
+
Wbuiltin-macro-redefined
C ObjC C++ ObjC++ CPP(warn_builtin_macro_redefined) CppReason(CPP_W_BUILTIN_MACRO_REDEFINED) Var(cpp_warn_builtin_macro_redefined) Init(1) Warning
Warn when a built-in preprocessor macro is undefined or redefined.
@@ -326,6 +377,13 @@ Wc++14-compat
C++ ObjC++ Var(warn_cxx14_compat) Warning LangEnabledBy(C++ ObjC++,Wall)
Warn about C++ constructs whose meaning differs between ISO C++ 2011 and ISO C++ 2014.
+Wc++1z-compat
+C++ ObjC++ Var(warn_cxx1z_compat) Warning LangEnabledBy(C++ ObjC++,Wall)
+Warn about C++ constructs whose meaning differs between ISO C++ 2014 and (forthcoming) ISO C++ 201z(7?).
+
+Wc++17-compat
+C++ ObjC++ Warning Alias(Wc++1z-compat) Undocumented
+
Wcast-qual
C ObjC C++ ObjC++ Var(warn_cast_qual) Warning
Warn about casts which discard qualifiers.
@@ -370,6 +428,10 @@ Wctor-dtor-privacy
C++ ObjC++ Var(warn_ctor_dtor_privacy) Warning
Warn when all constructors and destructors are private.
+Wdangling-else
+C ObjC C++ ObjC++ Var(warn_dangling_else) Warning LangEnabledBy(C ObjC C++ ObjC++,Wparentheses)
+Warn about dangling else.
+
Wdate-time
C ObjC C++ ObjC++ CPP(warn_date_time) CppReason(CPP_W_DATE_TIME) Var(cpp_warn_date_time) Init(0) Warning
Warn about __TIME__, __DATE__ and __TIMESTAMP__ usage.
@@ -406,6 +468,10 @@ Wdiv-by-zero
C ObjC C++ ObjC++ Var(warn_div_by_zero) Init(1) Warning
Warn about compile-time integer division by zero.
+Wduplicated-branches
+C ObjC C++ ObjC++ Var(warn_duplicated_branches) Init(0) Warning
+Warn about duplicated branches in if-else statements.
+
Wduplicated-cond
C ObjC C++ ObjC++ Var(warn_duplicated_cond) Init(0) Warning
Warn about duplicated conditions in an if-else-if chain.
@@ -420,7 +486,7 @@ Warn about an empty body in an if or else statement.
Wendif-labels
C ObjC C++ ObjC++ CPP(warn_endif_labels) CppReason(CPP_W_ENDIF_LABELS) Var(cpp_warn_endif_labels) Init(1) Warning LangEnabledBy(C ObjC C++ ObjC++,Wpedantic)
-Warn about stray tokens after #elif and #endif.
+Warn about stray tokens after #else and #endif.
Wenum-compare
C ObjC C++ ObjC++ Var(warn_enum_compare) Init(-1) Warning LangEnabledBy(C ObjC,Wall || Wc++-compat)
@@ -434,6 +500,10 @@ Werror-implicit-function-declaration
C ObjC RejectNegative Warning Alias(Werror=, implicit-function-declaration)
This switch is deprecated; use -Werror=implicit-function-declaration instead.
+Wextra
+C ObjC C++ ObjC++ Warning
+; in common.opt
+
Wfloat-conversion
C ObjC C++ ObjC++ Var(warn_float_conversion) Warning LangEnabledBy(C ObjC C++ ObjC++,Wconversion)
Warn for implicit type conversions that cause loss of floating point precision.
@@ -458,6 +528,11 @@ Wformat-nonliteral
C ObjC C++ ObjC++ Var(warn_format_nonliteral) Warning LangEnabledBy(C ObjC C++ ObjC++,Wformat=, warn_format >= 2, 0)
Warn about format strings that are not literals.
+Wformat-overflow
+C ObjC C++ LTO ObjC++ Warning Alias(Wformat-overflow=, 1, 0)
+Warn about function calls with format strings that write past the end
+of the destination region. Same as -Wformat-overflow=1.
+
Wformat-security
C ObjC C++ ObjC++ Var(warn_format_security) Warning LangEnabledBy(C ObjC C++ ObjC++,Wformat=, warn_format >= 2, 0)
Warn about possible security problems with format functions.
@@ -466,6 +541,11 @@ Wformat-signedness
C ObjC C++ ObjC++ Var(warn_format_signedness) Warning
Warn about sign differences with format functions.
+Wformat-truncation
+C ObjC C++ LTO ObjC++ Warning Alias(Wformat-truncation=, 1, 0)
+Warn about calls to snprintf and similar functions that truncate output.
+Same as -Wformat-truncation=1.
+
Wformat-y2k
C ObjC C++ ObjC++ Var(warn_format_y2k) Warning LangEnabledBy(C ObjC C++ ObjC++,Wformat=,warn_format >= 2, 0)
Warn about strftime formats yielding 2-digit years.
@@ -478,6 +558,15 @@ Wformat=
C ObjC C++ ObjC++ Joined RejectNegative UInteger Var(warn_format) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall, 1, 0)
Warn about printf/scanf/strftime/strfmon format string anomalies.
+Wformat-overflow=
+C ObjC C++ LTO ObjC++ Joined RejectNegative UInteger Var(warn_format_overflow) Warning LangEnabledBy(C ObjC C++ ObjC++,Wformat=, warn_format >= 1, 0)
+Warn about function calls with format strings that write past the end
+of the destination region.
+
+Wformat-truncation=
+C ObjC C++ ObjC++ Joined RejectNegative UInteger Var(warn_format_trunc) Warning LangEnabledBy(C ObjC C++ ObjC++,Wformat=, warn_format >= 1, 0)
+Warn about calls to snprintf and similar functions that truncate output.
+
Wignored-qualifiers
C C++ Var(warn_ignored_qualifiers) Warning EnabledBy(Wextra)
Warn whenever type qualifiers are ignored.
@@ -498,10 +587,18 @@ Wimplicit
C ObjC Var(warn_implicit) Warning LangEnabledBy(C ObjC,Wall)
Warn about implicit declarations.
+Wimplicit-fallthrough=
+LangEnabledBy(C ObjC C++ ObjC++,Wextra,3,0)
+; in common.opt
+
Wdouble-promotion
C ObjC C++ ObjC++ Var(warn_double_promotion) Warning
Warn about implicit conversions from \"float\" to \"double\".
+Wexpansion-to-defined
+C ObjC C++ ObjC++ CPP(warn_expansion_to_defined) CppReason(CPP_W_EXPANSION_TO_DEFINED) Var(cpp_warn_expansion_to_defined) Init(0) Warning EnabledBy(Wextra || Wpedantic)
+Warn if \"defined\" is used outside #if.
+
Wimplicit-function-declaration
C ObjC Var(warn_implicit_function_declaration) Init(-1) Warning LangEnabledBy(C ObjC,Wimplicit)
Warn about implicit function declarations.
@@ -521,6 +618,10 @@ Wint-conversion
C ObjC Var(warn_int_conversion) Init(1) Warning
Warn about incompatible integer to pointer and pointer to integer conversions.
+Wint-in-bool-context
+C ObjC C++ ObjC++ Var(warn_int_in_bool_context) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall)
+Warn for suspicious integer expressions in boolean context.
+
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.
@@ -565,6 +666,10 @@ Wmemset-transposed-args
C ObjC C++ ObjC++ Var(warn_memset_transposed_args) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall)
Warn about suspicious calls to memset where the third argument is constant literal zero and the second is not.
+Wmemset-elt-size
+C ObjC C++ ObjC++ Var(warn_memset_elt_size) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall)
+Warn about suspicious calls to memset where the third argument contains the number of elements not multiplied by the element size.
+
Wmisleading-indentation
C C++ Common Var(warn_misleading_indentation) Warning LangEnabledBy(C C++,Wall)
Warn when the indentation of the code does not reflect the block structure.
@@ -601,6 +706,16 @@ Wsizeof-array-argument
C ObjC C++ ObjC++ Var(warn_sizeof_array_argument) Warning Init(1)
Warn when sizeof is applied on a parameter declared as an array.
+Wstringop-overflow
+C ObjC C++ ObjC++ Warning Alias(Wstringop-overflow=, 2, 0)
+Warn about buffer overflow in string manipulation functions like memcpy
+and strcpy.
+
+Wstringop-overflow=
+C ObjC C++ ObjC++ Joined RejectNegative UInteger Var(warn_stringop_overflow) Init(2) Warning
+Under the control of Object Size type, warn about buffer overflow in string
+manipulation functions like memcpy and strcpy.
+
Wsuggest-attribute=format
C ObjC C++ ObjC++ Var(warn_suggest_attribute_format) Warning
Warn about functions which might be candidates for format attributes.
@@ -665,6 +780,10 @@ Wnoexcept
C++ ObjC++ Var(warn_noexcept) Warning
Warn when a noexcept expression evaluates to false even though the expression can't actually throw.
+Wnoexcept-type
+C++ ObjC++ Warning Var(warn_noexcept_type) LangEnabledBy(C++ ObjC++,Wabi || Wc++1z-compat)
+Warn if C++1z noexcept function type will change the mangled name of a symbol.
+
Wnon-template-friend
C++ ObjC++ Var(warn_nontemplate_friend) Init(1) Warning
Warn when non-templatized friend functions are declared within a template.
@@ -691,7 +810,7 @@ C ObjC C++ ObjC++ Warning Alias(Wnormalized=,nfc,none)
Wnormalized=
C ObjC C++ ObjC++ RejectNegative Joined Warning CPP(warn_normalize) CppReason(CPP_W_NORMALIZE) Init(normalized_C) Var(cpp_warn_normalize) Enum(cpp_normalize_level)
--Wnormalized=<none|id|nfc|nfkc> Warn about non-normalised Unicode strings.
+-Wnormalized=[none|id|nfc|nfkc] Warn about non-normalized Unicode strings.
; Required for these enum values.
SourceInclude
@@ -768,6 +887,10 @@ Wpointer-sign
C ObjC Var(warn_pointer_sign) Warning LangEnabledBy(C ObjC,Wall || Wpedantic)
Warn when a pointer differs in signedness in an assignment.
+Wpointer-compare
+C ObjC C++ ObjC++ Var(warn_pointer_compare) Init(1) Warning
+Warn when a pointer is compared with a zero character constant.
+
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.
@@ -796,6 +919,10 @@ Wredundant-decls
C ObjC C++ ObjC++ Var(warn_redundant_decls) Warning
Warn about multiple declarations of the same object.
+Wregister
+C++ ObjC++ Var(warn_register) Warning
+Warn about uses of register storage specifier.
+
Wreorder
C++ ObjC++ Var(warn_reorder) Warning LangEnabledBy(C++ ObjC++,Wall)
Warn when the compiler reorders code.
@@ -972,6 +1099,12 @@ Wvla
C ObjC C++ ObjC++ Var(warn_vla) Init(-1) Warning
Warn if a variable length array is used.
+Wvla-larger-than=
+C ObjC C++ ObjC++ Var(warn_vla_limit) Warning Joined RejectNegative UInteger
+-Wvla-larger-than=<number> Warn on unbounded uses of variable-length arrays, and
+on bounded uses of variable-length arrays whose bound can be
+larger than <number> bytes.
+
Wvolatile-register-var
C ObjC C++ ObjC++ Var(warn_volatile_register_var) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall)
Warn when a register variable is declared volatile.
@@ -1000,6 +1133,15 @@ Wsubobject-linkage
C++ ObjC++ Var(warn_subobject_linkage) Warning Init(1)
Warn if a class type has a base or a field whose type uses the anonymous namespace or depends on a type with no linkage.
+Wduplicate-decl-specifier
+C ObjC Var(warn_duplicate_decl_specifier) Warning LangEnabledBy(C ObjC,Wall)
+Warn when a declaration has duplicate const, volatile, restrict or _Atomic specifier.
+
+Wrestrict
+C ObjC C++ ObjC++ Var(warn_restrict) Warning LangEnabledBy(C ObjC C++ ObjC++)
+Warn when an argument passed to a restrict-qualified parameter aliases with
+another argument.
+
ansi
C ObjC C++ ObjC++
A synonym for -std=c89 (for C) or -std=c++98 (for C++).
@@ -1020,6 +1162,14 @@ fada-spec-parent=
C ObjC C++ ObjC++ RejectNegative Joined Var(ada_specs_parent)
-fada-spec-parent=unit Dump Ada specs as child units of given parent.
+faligned-new
+C++ ObjC++ Alias(faligned-new=,1,0)
+Support C++17 allocation of over-aligned types.
+
+faligned-new=
+C++ ObjC++ Joined RejectNegative Var(aligned_new_threshold) UInteger Init(-1)
+-faligned-new=<N> Use C++17 over-aligned type allocation for alignments greater than N.
+
fall-virtual
C++ ObjC++ Ignore Warn(switch %qs is no longer supported)
@@ -1078,7 +1228,13 @@ narrowing is on, field bounds are used. Otherwise full object bounds are used.
fchkp-narrow-to-innermost-array
C ObjC C++ ObjC++ LTO RejectNegative Report Var(flag_chkp_narrow_to_innermost_arrray)
Forces Pointer Bounds Checker to use bounds of the innermost arrays in case of
-nested static arryas access. By default outermost array is used.
+nested static arrays access. By default outermost array is used.
+
+fchkp-flexible-struct-trailing-arrays
+C ObjC C++ ObjC++ LTO Report Var(flag_chkp_flexible_struct_trailing_arrays)
+Forces Pointer Bounds Checker to treat all trailing arrays in structures as
+possibly flexible. By default only arrays fields with zero length or that are
+marked with attribute bnd_variable_size are treated as flexible.
fchkp-optimize
C ObjC C++ ObjC++ LTO Report Var(flag_chkp_optimize) Init(-1)
@@ -1162,6 +1318,10 @@ fconstexpr-depth=
C++ ObjC++ Joined RejectNegative UInteger Var(max_constexpr_depth) Init(512)
-fconstexpr-depth=<number> Specify maximum constexpr recursion depth.
+fconstexpr-loop-limit=
+C++ ObjC++ Joined RejectNegative UInteger Var(constexpr_loop_limit) Init(262144)
+-fconstexpr-loop-limit=<number> Specify maximum constexpr loop iteration count.
+
fdebug-cpp
C ObjC C++ ObjC++
Emit debug annotations during preprocessing.
@@ -1272,6 +1432,10 @@ fimplicit-templates
C++ ObjC++ Var(flag_implicit_templates) Init(1)
Emit implicit instantiations of templates.
+fnew-inheriting-ctors
+C++ ObjC++ Var(flag_new_inheriting_ctors) Init(1)
+Implement C++17 inheriting constructor semantics.
+
ffriend-injection
C++ ObjC++ Var(flag_friend_injection)
Inject friend functions into enclosing namespace.
@@ -1306,6 +1470,10 @@ C++ ObjC++ Joined Ignore Warn(switch %qs is no longer supported)
fnew-abi
C++ ObjC++ Ignore Warn(switch %qs is no longer supported)
+fnew-ttp-matching
+C++ ObjC++ Var(flag_new_ttp)
+Implement resolution of DR 150 for matching of template template arguments.
+
fnext-runtime
ObjC ObjC++ LTO Report RejectNegative Var(flag_next_runtime)
Generate code for NeXT (Apple Mac OS X) runtime environment.
@@ -1439,6 +1607,10 @@ 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.
+fprintf-return-value
+C ObjC C++ ObjC++ LTO Optimization Var(flag_printf_return_value) Init(1)
+Treat known sprintf return values as constants.
+
freplace-objc-classes
ObjC ObjC++ LTO Var(flag_replace_objc_classes)
Used in Fix-and-Continue mode to indicate that object files may be swapped in at runtime.
@@ -1475,8 +1647,8 @@ fsquangle
C++ ObjC++ Ignore Warn(switch %qs is no longer supported)
fsso-struct=
-C ObjC Joined Enum(sso_struct) Var(default_sso) Init(SSO_NATIVE)
--fsso-struct=[big-endian|little-endian] Set the default scalar storage order.
+C ObjC Joined RejectNegative Enum(sso_struct) Var(default_sso) Init(SSO_NATIVE)
+-fsso-struct=[big-endian|little-endian|native] Set the default scalar storage order.
Enum
Name(sso_struct) Type(enum scalar_storage_order_kind) UnknownError(unrecognized scalar storage order value %qs)
@@ -1487,6 +1659,9 @@ Enum(sso_struct) String(big-endian) Value(SSO_BIG_ENDIAN)
EnumValue
Enum(sso_struct) String(little-endian) Value(SSO_LITTLE_ENDIAN)
+EnumValue
+Enum(sso_struct) String(native) Value(SSO_NATIVE)
+
fstats
C++ ObjC++ Var(flag_detailed_statistics)
Display statistics accumulated during compilation.
@@ -1498,6 +1673,28 @@ Assume that values of enumeration type are always within the minimum range of th
fstrict-prototype
C++ ObjC++ Ignore Warn(switch %qs is no longer supported)
+fstrong-eval-order
+C++ ObjC++ Common Alias(fstrong-eval-order=, all, none)
+Follow the C++17 evaluation order requirements for assignment expressions,
+shift, member function calls, etc.
+
+fstrong-eval-order=
+C++ ObjC++ Common Var(flag_strong_eval_order) Joined Enum(strong_eval_order) RejectNegative Init(-1)
+Follow the C++17 evaluation order requirements for assignment expressions,
+shift, member function calls, etc.
+
+Enum
+Name(strong_eval_order) Type(int)
+
+EnumValue
+Enum(strong_eval_order) String(none) Value(0)
+
+EnumValue
+Enum(strong_eval_order) String(some) Value(1)
+
+EnumValue
+Enum(strong_eval_order) String(all) Value(2)
+
ftabstop=
C ObjC C++ ObjC++ Joined RejectNegative UInteger
-ftabstop=<number> Distance between tab stops for column reporting.
@@ -1573,7 +1770,7 @@ 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)
+ObjC ObjC++ Driver Var(flag_gen_declaration)
Dump declarations to a .decl file.
femit-struct-debug-baseonly
@@ -1589,7 +1786,7 @@ C ObjC C++ ObjC++ Joined
-femit-struct-debug-detailed=<spec-list> Detailed reduced debug info for structs.
fext-numeric-literals
-C++ ObjC++
+C++ ObjC++ Var(flag_ext_numeric_literals) Init(1)
Interpret imaginary, fixed-point, or other gnu number suffix as the corresponding
number literal rather than a user-defined number literal.
diff --git a/gcc/c-family/cilk.c b/gcc/c-family/cilk.c
index 0b876b9fd6..43478fff91 100644
--- a/gcc/c-family/cilk.c
+++ b/gcc/c-family/cilk.c
@@ -1,6 +1,6 @@
/* This file is part of the Intel(R) Cilk(TM) Plus support
This file contains the CilkPlus Intrinsics
- Copyright (C) 2013-2016 Free Software Foundation, Inc.
+ Copyright (C) 2013-2017 Free Software Foundation, Inc.
Contributed by Balaji V. Iyer <balaji.v.iyer@intel.com>,
Intel Corporation
@@ -185,7 +185,7 @@ call_graph_add_fn (tree fndecl)
A comparison to constant is simple enough to allow, and
is used to convert to bool. */
-static bool
+bool
cilk_ignorable_spawn_rhs_op (tree exp)
{
enum tree_code code = TREE_CODE (exp);
@@ -223,8 +223,8 @@ unwrap_cilk_spawn_stmt (tree *tp, int *walk_subtrees, void *)
/* Returns true when EXP is a CALL_EXPR with _Cilk_spawn in front. Unwraps
CILK_SPAWN_STMT wrapper from the CALL_EXPR in *EXP0 statement. */
-static bool
-recognize_spawn (tree exp, tree *exp0)
+bool
+cilk_recognize_spawn (tree exp, tree *exp0)
{
bool spawn_found = false;
if (TREE_CODE (exp) == CILK_SPAWN_STMT)
@@ -292,7 +292,7 @@ cilk_detect_spawn_and_unwrap (tree *exp0)
/* Now we should have a CALL_EXPR with a CILK_SPAWN_STMT wrapper around
it, or return false. */
- if (recognize_spawn (exp, exp0))
+ if (cilk_recognize_spawn (exp, exp0))
return true;
return false;
}
@@ -312,8 +312,9 @@ create_cilk_helper_decl (struct wrapper_data *wd)
gcc_unreachable ();
clean_symbol_name (name);
- tree fndecl = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL,
- get_identifier (name), wd->fntype);
+
+ tree fndecl = build_decl (DECL_SOURCE_LOCATION (current_function_decl),
+ FUNCTION_DECL, get_identifier (name), wd->fntype);
TREE_PUBLIC (fndecl) = 0;
TREE_STATIC (fndecl) = 1;
@@ -795,9 +796,13 @@ cilk_gimplify_call_params_in_spawned_fn (tree *expr_p, gimple_seq *pre_p)
fix_parm_expr = &TREE_OPERAND (*expr_p, 1);
if (TREE_CODE (*fix_parm_expr) == CALL_EXPR)
- for (ii = 0; ii < call_expr_nargs (*fix_parm_expr); ii++)
- gimplify_arg (&CALL_EXPR_ARG (*fix_parm_expr, ii), pre_p,
- EXPR_LOCATION (*fix_parm_expr));
+ {
+ /* Cilk outlining assumes GENERIC bodies, avoid leaking SSA names
+ via parameters. */
+ for (ii = 0; ii < call_expr_nargs (*fix_parm_expr); ii++)
+ gimplify_arg (&CALL_EXPR_ARG (*fix_parm_expr, ii), pre_p,
+ EXPR_LOCATION (*fix_parm_expr), false);
+ }
}
@@ -1092,6 +1097,7 @@ extract_free_variables (tree t, struct wrapper_data *wd,
case RESULT_DECL:
if (wd->type != CILK_BLOCK_SPAWN)
TREE_ADDRESSABLE (t) = 1;
+ /* FALLTHRU */
case VAR_DECL:
case PARM_DECL:
if (!is_global_var (t))
@@ -1250,6 +1256,21 @@ extract_free_variables (tree t, struct wrapper_data *wd,
return;
case AGGR_INIT_EXPR:
+ {
+ int len = 0;
+ int ii = 0;
+ extract_free_variables (TREE_OPERAND (t, 1), wd, ADD_READ);
+ if (TREE_CODE (TREE_OPERAND (t, 0)) == INTEGER_CST)
+ {
+ len = TREE_INT_CST_LOW (TREE_OPERAND (t, 0));
+
+ for (ii = 3; ii < len; ii++)
+ extract_free_variables (TREE_OPERAND (t, ii), wd, ADD_READ);
+ extract_free_variables (TREE_TYPE (t), wd, ADD_READ);
+ }
+ break;
+ }
+
case CALL_EXPR:
{
int len = 0;
diff --git a/gcc/c-family/cppspec.c b/gcc/c-family/cppspec.c
index 18cd61ceeb..abe7d91fe8 100644
--- a/gcc/c-family/cppspec.c
+++ b/gcc/c-family/cppspec.c
@@ -1,5 +1,5 @@
/* Specific flags and argument handling of the C preprocessor.
- Copyright (C) 1999-2016 Free Software Foundation, Inc.
+ Copyright (C) 1999-2017 Free Software Foundation, Inc.
This file is part of GCC.
diff --git a/gcc/c-family/stub-objc.c b/gcc/c-family/stub-objc.c
index e26207e302..33dc2a1abd 100644
--- a/gcc/c-family/stub-objc.c
+++ b/gcc/c-family/stub-objc.c
@@ -1,7 +1,7 @@
/* Stub functions for Objective-C and Objective-C++ routines
that are called from within the C and C++ front-ends,
respectively.
- Copyright (C) 1991-2016 Free Software Foundation, Inc.
+ Copyright (C) 1991-2017 Free Software Foundation, Inc.
This file is part of GCC.