diff options
Diffstat (limited to 'gcc/c-family')
-rw-r--r-- | gcc/c-family/ChangeLog | 385 | ||||
-rw-r--r-- | gcc/c-family/c-ada-spec.cc | 26 | ||||
-rw-r--r-- | gcc/c-family/c-attribs.cc | 232 | ||||
-rw-r--r-- | gcc/c-family/c-common.cc | 143 | ||||
-rw-r--r-- | gcc/c-family/c-common.def | 3 | ||||
-rw-r--r-- | gcc/c-family/c-common.h | 16 | ||||
-rw-r--r-- | gcc/c-family/c-cppbuiltin.cc | 82 | ||||
-rw-r--r-- | gcc/c-family/c-format.cc | 27 | ||||
-rw-r--r-- | gcc/c-family/c-format.h | 1 | ||||
-rw-r--r-- | gcc/c-family/c-gimplify.cc | 27 | ||||
-rw-r--r-- | gcc/c-family/c-indentation.cc | 21 | ||||
-rw-r--r-- | gcc/c-family/c-lex.cc | 2 | ||||
-rw-r--r-- | gcc/c-family/c-omp.cc | 313 | ||||
-rw-r--r-- | gcc/c-family/c-opts.cc | 89 | ||||
-rw-r--r-- | gcc/c-family/c-pragma.cc | 19 | ||||
-rw-r--r-- | gcc/c-family/c-ubsan.cc | 321 | ||||
-rw-r--r-- | gcc/c-family/c-warn.cc | 4 | ||||
-rw-r--r-- | gcc/c-family/c.opt | 26 | ||||
-rw-r--r-- | gcc/c-family/c.opt.urls | 18 | ||||
-rw-r--r-- | gcc/c-family/known-headers.cc | 7 | ||||
-rw-r--r-- | gcc/c-family/known-headers.h | 4 |
21 files changed, 1571 insertions, 195 deletions
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 1572c8b..9725521 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,388 @@ +2025-09-08 Eric Botcazou <ebotcazou@adacore.com> + + PR ada/121544 + * c-ada-spec.cc (dump_ada_node) <POINTER_TYPE>: Dump the name of + anonymous tagged pointed-to types specially. + (dump_nested_type) <POINTER_TYPE>: Recurse on anonymous pointed-to + types declared in the same file. + Set TREE_VISITED on the underlying DECL of the field type, if any. + +2025-08-27 Jakub Jelinek <jakub@redhat.com> + + PR target/121520 + * c-cppbuiltin.cc (c_cpp_builtins): Properly call cpp_warn + for __STDCPP_FLOAT<NN>_T__ if FLOATN_NX_TYPE_NODE (i) is NULL + for C++23 for non-extended types and don't call cpp_warn for + extended types. + +2025-08-18 Indu Bhagat <indu.bhagat@oracle.com> + + * c-attribs.cc (add_no_sanitize_value): Use 'sanitize_code_type' + instead of 'unsigned int'. + (handle_no_sanitize_attribute): Likewise. + (handle_no_sanitize_address_attribute): Likewise. + (handle_no_sanitize_thread_attribute): Likewise. + (handle_no_address_safety_analysis_attribute): Likewise. + * c-common.h (add_no_sanitize_value): Likewise. + +2025-08-15 Jakub Jelinek <jakub@redhat.com> + + PR c++/121552 + * c.opt (Wnon-c-typedef-for-linkage): New option. + * c.opt.urls: Regenerate. + +2025-08-15 Jakub Jelinek <jakub@redhat.com> + + PR preprocessor/120778 + PR target/121520 + * c-cppbuiltin.cc (c_cpp_builtins): Implement C++26 DR 2581. Add + cpp_define_warn lambda and use it as well as cpp_warn where needed. + In the if (c_dialect_cxx ()) block with __cpp_* predefinitions add + cpp_define lambda. Formatting fixes. + +2025-08-15 Qing Zhao <qing.zhao@oracle.com> + + * c-gimplify.cc (is_address_with_access_with_size): New function. + (ubsan_walk_array_refs_r): Instrument an INDIRECT_REF whose base + address is .ACCESS_WITH_SIZE or an address computation whose base + address is .ACCESS_WITH_SIZE. + * c-ubsan.cc (ubsan_instrument_bounds_pointer_address): New function. + (struct factor_t): New structure. + (get_factors_from_mul_expr): New function. + (get_index_from_offset): New function. + (get_index_from_pointer_addr_expr): New function. + (is_instrumentable_pointer_array_address): New function. + (ubsan_array_ref_instrumented_p): Change prototype. + Handle MEM_REF in addtional to ARRAY_REF. + (ubsan_maybe_instrument_array_ref): Handle MEM_REF in addtional + to ARRAY_REF. + +2025-08-15 Qing Zhao <qing.zhao@oracle.com> + + * c-attribs.cc (handle_counted_by_attribute): Accept counted_by + attribute for pointer fields. + +2025-08-13 Jakub Jelinek <jakub@redhat.com> + + PR c++/120776 + * c-cppbuiltin.cc (c_cpp_builtins): Predefine + __cpp_expansion_statements=202506L for C++26. + +2025-08-08 David Malcolm <dmalcolm@redhat.com> + + * c-indentation.cc (should_warn_for_misleading_indentation): + Update for moving diagnostics::context::m_tabstop into + diagnostics::column_options. + * c-opts.cc (c_common_post_options): Likewise. + +2025-08-07 Jakub Jelinek <jakub@redhat.com> + + PR c++/117783 + * c-cppbuiltin.cc (c_cpp_builtins): Change __cpp_structured_bindings + predefined value for C++26 from 202403L to 202411L. + +2025-08-07 Jakub Jelinek <jakub@redhat.com> + + PR preprocessor/120778 + * c.opt (Wkeyword-macro): New option. + * c.opt.urls: Regenerate. + * c-common.h (cxx_dialect): Comment formatting fix. + * c-opts.cc (c_common_post_options): Default to + -Wkeyword-macro for C++26 if pedantic. + +2025-08-06 Alexandre Oliva <oliva@adacore.com> + + * c-attribs.cc (handle_hardbool_attribute): Create distinct + enumeration types, with structural equality. Handle + base type qualifiers. + +2025-08-02 Martin Uecker <uecker@tugraz.at> + + * c-attribs.cc (handle_argspec_attribute): Update. + (build_arg_spec): New function. + (build_attr_access_from_parms): Rewrite `arg spec' handling. + +2025-07-25 David Malcolm <dmalcolm@redhat.com> + + * c-common.cc: Make diagnostics::context::m_source_printing + private. + * c-format.cc: Likewise. + * c-opts.cc: Likewise. + +2025-07-25 David Malcolm <dmalcolm@redhat.com> + + * c-common.cc: Update usage of "diagnostic_info" to explicitly + refer to "diagnostics::diagnostic_info". + * c-opts.cc: Likewise. + +2025-07-25 David Malcolm <dmalcolm@redhat.com> + + * c-format.cc: Update for file_cache and char_span moving from + input.h to diagnostics/file-cache.h and into the "diagnostics::" + namespace. + * c-indentation.cc: Likewise. + +2025-07-25 David Malcolm <dmalcolm@redhat.com> + + * c-common.cc (c_family_tests): Add include of + "diagnostics/diagnostics-selftests.h". Replace + c_diagnostic_cc_tests with + diagnostics::selftest::context_cc_tests. + * c-common.h: Drop c_diagnostic_cc_tests decl. + +2025-07-25 David Malcolm <dmalcolm@redhat.com> + + * c-common.cc: Update for diagnostic_t becoming + enum class diagnostics::kind. + * c-format.cc: Likewise. + * c-lex.cc: Likewise. + * c-opts.cc: Likewise. + * c-pragma.cc: Likewise. + * c-warn.cc: Likewise. + +2025-07-25 David Malcolm <dmalcolm@redhat.com> + + * c-common.cc: Update for renaming of diagnostic_option_id to + diagnostics::option_id. + * c-common.h: Likewise. + * c-cppbuiltin.cc: Likewise. + * known-headers.cc: Likewise. + * known-headers.h: Likewise. + +2025-07-25 David Malcolm <dmalcolm@redhat.com> + + * c-common.cc: Update comment for renaming of edit_context. + +2025-07-25 David Malcolm <dmalcolm@redhat.com> + + * c-format.cc (test_type_mismatch_range_labels): Update for + move of selftest::test_diagnostic_context to + diagnostics::selftest::test_context. + +2025-07-25 David Malcolm <dmalcolm@redhat.com> + + * c-format.cc: Update for move of selftest-diagnostic.h to + diagnostics/selftest-context.h. + +2025-07-25 David Malcolm <dmalcolm@redhat.com> + + * c-common.h: Update for diagnostic_context becoming + diagnostics::context. + * c-opts.cc: Likewise. + +2025-07-25 David Malcolm <dmalcolm@redhat.com> + + * c-opts.cc (c_diagnostic_text_finalizer): Add "m_" prefix to + fields of diagnostic_info. + +2025-07-25 David Malcolm <dmalcolm@redhat.com> + + * c-opts.cc: Update for move of "diagnostic-macro-unwinding.h" + to "diagnostics/macro-unwinding.h". + +2025-07-25 David Malcolm <dmalcolm@redhat.com> + + * c-opts.cc: Update for move of diagnostics output formats into + namespace "diagnostics" as "sinks". + +2025-07-16 Kwok Cheung Yeung <kcyeung@baylibre.com> + + * c-omp.cc (c_finish_omp_depobj): Use OMP_ITERATOR_DECL_P. + +2025-07-16 Alfie Richards <alfie.richards@arm.com> + + * c-attribs.cc (handle_target_clones_attribute): Change to use + get_clone_versions. + +2025-07-16 Alfie Richards <alfie.richards@arm.com> + + * c-format.cc (local_string_slice_node): New node type. + (asm_fprintf_char_table): New entry. + (init_dynamic_diag_info): Add support for string_slice. + * c-format.h (T_STRING_SLICE): New node type. + +2025-07-15 Jakub Jelinek <jakub@redhat.com> + Jason Merrill <jason@redhat.com> + + PR c/44677 + * c-opts.cc (c_common_post_options): Change + warn_unused_but_set_parameter and warn_unused_but_set_variable + from 1 to 3 if they were set only implicitly. + * c-attribs.cc (build_attr_access_from_parms): Remove unused + but set variable nelts. + +2025-07-11 Jakub Jelinek <jakub@redhat.com> + + PR c++/119064 + * c.opt (Wc++26-compat): New option. + * c.opt.urls: Regenerate. + * c-opts.cc (c_common_post_options): Clear warn_cxx26_compat for + C++26 or later. + * c-cppbuiltin.cc (c_cpp_builtins): For C++26 predefine + __cpp_trivial_relocatability=202502L. + +2025-07-10 Jakub Jelinek <jakub@redhat.com> + + PR c++/117785 + * c-cppbuiltin.cc (c_cpp_builtins): Predefine + __cpp_constexpr_exceptions=202411L for C++26. + +2025-07-10 Qing Zhao <qing.zhao@oracle.com> + + * c-ubsan.cc (get_bound_from_access_with_size): Adjust the position + of the arguments per the new design. + +2025-07-07 Qing Zhao <qing.zhao@oracle.com> + + Revert: + 2025-07-01 Qing Zhao <qing.zhao@oracle.com> + + * c-attribs.cc (handle_counted_by_attribute): Accept counted_by + attribute for pointer fields. + +2025-07-07 Qing Zhao <qing.zhao@oracle.com> + + Revert: + 2025-07-01 Qing Zhao <qing.zhao@oracle.com> + + * c-gimplify.cc (is_address_with_access_with_size): New function. + (ubsan_walk_array_refs_r): Instrument an INDIRECT_REF whose base + address is .ACCESS_WITH_SIZE or an address computation whose base + address is .ACCESS_WITH_SIZE. + * c-ubsan.cc (ubsan_instrument_bounds_pointer_address): New function. + (struct factor_t): New structure. + (get_factors_from_mul_expr): New function. + (get_index_from_offset): New function. + (get_index_from_pointer_addr_expr): New function. + (is_instrumentable_pointer_array_address): New function. + (ubsan_array_ref_instrumented_p): Change prototype. + Handle MEM_REF in addtional to ARRAY_REF. + (ubsan_maybe_instrument_array_ref): Handle MEM_REF in addtional + to ARRAY_REF. + +2025-07-07 Jason Merrill <jason@redhat.com> + + PR c++/120917 + * c.opt: Add -Wno-abbreviated-auto-in-template-arg. + * c.opt.urls: Regenerate. + +2025-07-04 Jakub Jelinek <jakub@redhat.com> + + PR c/120837 + * c-common.cc (pointer_int_sum): Rewrite the intop PLUS_EXPR or + MINUS_EXPR optimization into extension of both intop operands, + their separate multiplication and then addition/subtraction followed + by rest of pointer_int_sum handling after the multiplication. + +2025-07-01 Qing Zhao <qing.zhao@oracle.com> + + * c-gimplify.cc (is_address_with_access_with_size): New function. + (ubsan_walk_array_refs_r): Instrument an INDIRECT_REF whose base + address is .ACCESS_WITH_SIZE or an address computation whose base + address is .ACCESS_WITH_SIZE. + * c-ubsan.cc (ubsan_instrument_bounds_pointer_address): New function. + (struct factor_t): New structure. + (get_factors_from_mul_expr): New function. + (get_index_from_offset): New function. + (get_index_from_pointer_addr_expr): New function. + (is_instrumentable_pointer_array_address): New function. + (ubsan_array_ref_instrumented_p): Change prototype. + Handle MEM_REF in addtional to ARRAY_REF. + (ubsan_maybe_instrument_array_ref): Handle MEM_REF in addtional + to ARRAY_REF. + +2025-07-01 Qing Zhao <qing.zhao@oracle.com> + + * c-attribs.cc (handle_counted_by_attribute): Accept counted_by + attribute for pointer fields. + +2025-06-30 Jakub Jelinek <jakub@redhat.com> + + PR c/120520 + PR c/117023 + * c-attribs.cc (c_common_gnu_attributes): Allow 2 or 3 arguments for + nonnull_if_nonzero attribute instead of only 2. + (handle_nonnull_if_nonzero_attribute): Handle 3 argument + nonnull_if_nonzero. + * c-common.cc (struct nonnull_arg_ctx): Rename other member to other1, + add other2 member. + (check_function_nonnull): Clear a if nonnull attribute has an + argument. Adjust for nonnull_arg_ctx changes. Handle 3 argument + nonnull_if_nonzero attribute. + (check_nonnull_arg): Adjust for nonnull_arg_ctx changes, emit different + diagnostics for 3 argument nonnull_if_nonzero attributes. + (check_function_arguments): Adjust ctx var initialization. + +2025-06-27 Jakub Jelinek <jakub@redhat.com> + + PR c++/120777 + * c-cppbuiltin.cc (c_cpp_builtins): Predefine + __cpp_constexpr_virtual_inheritance=202506L for C++26. + +2025-06-26 David Malcolm <dmalcolm@redhat.com> + + * c-opts.cc (c_common_diagnostics_set_defaults): Use + diagnostic_context::set_permissive_option. + +2025-06-23 Tobias Burnus <tburnus@baylibre.com> + + * c-omp.cc (c_finish_oacc_wait): Handle if clause. + +2025-06-16 Jason Merrill <jason@redhat.com> + + * c.opt: Add -Wsfinae-incomplete. + * c.opt.urls: Regenerate. + +2025-06-12 Gwenole Beauchesne <gb.devel@gmail.com> + Andrew Pinski <quic_apinski@quicinc.com> + + PR c++/41201 + PR c++/48026 + * c-pragma.cc (init_pragma): Use c_register_pragma_with_early_handler + instead of c_register_pragma for `#pragma GCC optimize`. + +2025-06-03 Martin Uecker <uecker@tugraz.at> + + PR c/120078 + * c.opt (Wjump-misses-init): Fix typo. + +2025-05-30 Julian Brown <julian@codesourcery.com> + Tobias Burnus <tburnus@baylibre.com> + + * c-common.h (c_omp_region_type): Add C_ORT_DECLARE_MAPPER and + C_ORT_OMP_DECLARE_MAPPER codes. + (omp_mapper_list): Add forward declaration. + (c_omp_find_nested_mappers, c_omp_instantiate_mappers): Add prototypes. + * c-omp.cc (c_omp_find_nested_mappers): New function. + (remap_mapper_decl_info): New struct. + (remap_mapper_decl_1, omp_instantiate_mapper, + c_omp_instantiate_mappers): New functions. + +2025-05-27 Alejandro Colomar <alx@kernel.org> + Martin Uecker <uecker@tugraz.at> + + PR c/117025 + * c-common.h (enum rid): Add RID_COUNTOF. + (c_countof_type): New function prototype. + * c-common.def (COUNTOF_EXPR): New tree. + * c-common.cc (c_common_reswords): Add RID_COUNTOF entry. + (c_countof_type): New function. + +2025-05-23 Jason Merrill <jason@redhat.com> + + * c-format.cc (flag_chars_t::validate): Control quoting warnings + with -Wformat-diag. + +2025-05-15 Jason Merrill <jason@redhat.com> + + * c-opts.cc (c_common_post_options): Set flag_coroutines. + (set_std_cxx20, set_std_cxx23, set_std_cxx26): Not here. + +2025-05-03 Jason Merrill <jason@redhat.com> + + * c-opts.cc (c_common_post_options): Let plain -Wabi warn + about changes in a future version. + 2025-04-28 David Malcolm <dmalcolm@redhat.com> * c-pretty-print.cc: Drop include of "make-unique.h". diff --git a/gcc/c-family/c-ada-spec.cc b/gcc/c-family/c-ada-spec.cc index c7ae032..42d75b4 100644 --- a/gcc/c-family/c-ada-spec.cc +++ b/gcc/c-family/c-ada-spec.cc @@ -2442,8 +2442,14 @@ dump_ada_node (pretty_printer *pp, tree node, tree type, int spc, break; } - dump_ada_node (pp, ref_type, ref_type, spc, is_access, - true); + /* Dump anonymous tagged types specially. */ + if (TYPE_NAME (ref_type) + || (!RECORD_OR_UNION_TYPE_P (ref_type) + && TREE_CODE (ref_type) != ENUMERAL_TYPE)) + dump_ada_node (pp, ref_type, ref_type, spc, is_access, + true); + else + dump_anonymous_type_name (pp, ref_type); } } } @@ -2699,7 +2705,16 @@ dump_nested_type (pretty_printer *pp, tree field, tree t, int spc) { case POINTER_TYPE: tmp = TREE_TYPE (field_type); - dump_forward_type (pp, tmp, t, spc); + decl = get_underlying_decl (tmp); + if (TYPE_NAME (tmp) || !decl || DECL_NAME (decl)) + dump_forward_type (pp, tmp, t, spc); + else if (DECL_SOURCE_FILE (decl) == DECL_SOURCE_FILE (t) + && !TREE_VISITED (decl)) + { + /* Generate full declaration. */ + dump_nested_type (pp, decl, t, spc); + TREE_VISITED (decl) = 1; + } break; case ARRAY_TYPE: @@ -2773,6 +2788,11 @@ dump_nested_type (pretty_printer *pp, tree field, tree t, int spc) default: break; } + + /* Make sure not to output the nested type twice in C++. */ + decl = get_underlying_decl (field_type); + if (decl) + TREE_VISITED (decl) = 1; } /* Hash table of overloaded names that we cannot support. It is needed even diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc index 5a0e3d3..1e3a94e 100644 --- a/gcc/c-family/c-attribs.cc +++ b/gcc/c-family/c-attribs.cc @@ -489,7 +489,7 @@ const struct attribute_spec c_common_gnu_attributes[] = handle_tls_model_attribute, NULL }, { "nonnull", 0, -1, false, true, true, false, handle_nonnull_attribute, NULL }, - { "nonnull_if_nonzero", 2, 2, false, true, true, false, + { "nonnull_if_nonzero", 2, 3, false, true, true, false, handle_nonnull_if_nonzero_attribute, NULL }, { "nonstring", 0, 0, true, false, false, false, handle_nonstring_attribute, NULL }, @@ -1128,11 +1128,16 @@ handle_hardbool_attribute (tree *node, tree name, tree args, } tree orig = *node; - *node = build_duplicate_type (orig); + /* Drop qualifiers from the base type. Keep attributes, so that, in the odd + chance attributes are applicable and relevant to the base type, if they + are specified first, or through a typedef, they wouldn't be dropped on the + floor here. */ + tree unqual = build_qualified_type (orig, TYPE_UNQUALIFIED); + *node = build_distinct_type_copy (unqual); TREE_SET_CODE (*node, ENUMERAL_TYPE); - ENUM_UNDERLYING_TYPE (*node) = orig; - TYPE_CANONICAL (*node) = TYPE_CANONICAL (orig); + ENUM_UNDERLYING_TYPE (*node) = unqual; + SET_TYPE_STRUCTURAL_EQUALITY (*node); tree false_value; if (args) @@ -1191,7 +1196,13 @@ handle_hardbool_attribute (tree *node, tree name, tree args, gcc_checking_assert (!TYPE_CACHED_VALUES_P (*node)); TYPE_VALUES (*node) = values; - TYPE_NAME (*node) = orig; + TYPE_NAME (*node) = unqual; + + if (TYPE_QUALS (orig) != TYPE_QUALS (*node)) + { + *node = build_qualified_type (*node, TYPE_QUALS (orig)); + TYPE_NAME (*node) = orig; + } return NULL_TREE; } @@ -1409,23 +1420,24 @@ handle_cold_attribute (tree *node, tree name, tree ARG_UNUSED (args), /* Add FLAGS for a function NODE to no_sanitize_flags in DECL_ATTRIBUTES. */ void -add_no_sanitize_value (tree node, unsigned int flags) +add_no_sanitize_value (tree node, sanitize_code_type flags) { tree attr = lookup_attribute ("no_sanitize", DECL_ATTRIBUTES (node)); if (attr) { - unsigned int old_value = tree_to_uhwi (TREE_VALUE (attr)); + sanitize_code_type old_value = + tree_to_sanitize_code_type (TREE_VALUE (attr)); flags |= old_value; if (flags == old_value) return; - TREE_VALUE (attr) = build_int_cst (unsigned_type_node, flags); + TREE_VALUE (attr) = build_int_cst (uint64_type_node, flags); } else DECL_ATTRIBUTES (node) = tree_cons (get_identifier ("no_sanitize"), - build_int_cst (unsigned_type_node, flags), + build_int_cst (uint64_type_node, flags), DECL_ATTRIBUTES (node)); } @@ -1436,7 +1448,7 @@ static tree handle_no_sanitize_attribute (tree *node, tree name, tree args, int, bool *no_add_attrs) { - unsigned int flags = 0; + sanitize_code_type flags = 0; *no_add_attrs = true; if (TREE_CODE (*node) != FUNCTION_DECL) { @@ -1473,7 +1485,7 @@ handle_no_sanitize_address_attribute (tree *node, tree name, tree, int, if (TREE_CODE (*node) != FUNCTION_DECL) warning (OPT_Wattributes, "%qE attribute ignored", name); else - add_no_sanitize_value (*node, SANITIZE_ADDRESS); + add_no_sanitize_value (*node, (sanitize_code_type) SANITIZE_ADDRESS); return NULL_TREE; } @@ -1489,7 +1501,7 @@ handle_no_sanitize_thread_attribute (tree *node, tree name, tree, int, if (TREE_CODE (*node) != FUNCTION_DECL) warning (OPT_Wattributes, "%qE attribute ignored", name); else - add_no_sanitize_value (*node, SANITIZE_THREAD); + add_no_sanitize_value (*node, (sanitize_code_type) SANITIZE_THREAD); return NULL_TREE; } @@ -1506,7 +1518,7 @@ handle_no_address_safety_analysis_attribute (tree *node, tree name, tree, int, if (TREE_CODE (*node) != FUNCTION_DECL) warning (OPT_Wattributes, "%qE attribute ignored", name); else - add_no_sanitize_value (*node, SANITIZE_ADDRESS); + add_no_sanitize_value (*node, (sanitize_code_type) SANITIZE_ADDRESS); return NULL_TREE; } @@ -2906,22 +2918,53 @@ handle_counted_by_attribute (tree *node, tree name, " declaration %q+D", name, decl); *no_add_attrs = true; } - /* This attribute only applies to field with array type. */ - else if (TREE_CODE (TREE_TYPE (decl)) != ARRAY_TYPE) + /* This attribute only applies to a field with array type or pointer type. */ + else if (TREE_CODE (TREE_TYPE (decl)) != ARRAY_TYPE + && TREE_CODE (TREE_TYPE (decl)) != POINTER_TYPE) { error_at (DECL_SOURCE_LOCATION (decl), - "%qE attribute is not allowed for a non-array field", - name); + "%qE attribute is not allowed for a non-array" + " or non-pointer field", name); *no_add_attrs = true; } /* This attribute only applies to a C99 flexible array member type. */ - else if (! c_flexible_array_member_type_p (TREE_TYPE (decl))) + else if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE + && !c_flexible_array_member_type_p (TREE_TYPE (decl))) { error_at (DECL_SOURCE_LOCATION (decl), "%qE attribute is not allowed for a non-flexible" " array member field", name); *no_add_attrs = true; } + /* This attribute cannot be applied to a pointer to void type. */ + else if (TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) == VOID_TYPE) + { + error_at (DECL_SOURCE_LOCATION (decl), + "%qE attribute is not allowed for a pointer to void", + name); + *no_add_attrs = true; + } + /* This attribute cannot be applied to a pointer to function type. */ + else if (TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) == FUNCTION_TYPE) + { + error_at (DECL_SOURCE_LOCATION (decl), + "%qE attribute is not allowed for a pointer to" + " function", name); + *no_add_attrs = true; + } + /* This attribute cannot be applied to a pointer to structure or union + with flexible array member. */ + else if (TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE + && RECORD_OR_UNION_TYPE_P (TREE_TYPE (TREE_TYPE (decl))) + && TYPE_INCLUDES_FLEXARRAY (TREE_TYPE (TREE_TYPE (decl)))) + { + error_at (DECL_SOURCE_LOCATION (decl), + "%qE attribute is not allowed for a pointer to" + " structure or union with flexible array member", name); + *no_add_attrs = true; + } /* The argument should be an identifier. */ else if (TREE_CODE (argval) != IDENTIFIER_NODE) { @@ -2930,7 +2973,8 @@ handle_counted_by_attribute (tree *node, tree name, *no_add_attrs = true; } /* Issue error when there is a counted_by attribute with a different - field as the argument for the same flexible array member field. */ + field as the argument for the same flexible array member or + pointer field. */ else if (old_counted_by != NULL_TREE) { tree old_fieldname = TREE_VALUE (TREE_VALUE (old_counted_by)); @@ -4120,10 +4164,11 @@ handle_argspec_attribute (tree *, tree, tree args, int, bool *) { /* Verify the attribute has one or two arguments and their kind. */ gcc_assert (args && TREE_CODE (TREE_VALUE (args)) == STRING_CST); - for (tree next = TREE_CHAIN (args); next; next = TREE_CHAIN (next)) + if (TREE_CHAIN (args)) { - tree val = TREE_VALUE (next); - gcc_assert (DECL_P (val) || EXPR_P (val)); + tree val = TREE_VALUE (TREE_CHAIN (args)); + gcc_assert (!TREE_CHAIN (TREE_CHAIN (args))); + gcc_assert (TYPE_P (val)); } return NULL_TREE; } @@ -5034,12 +5079,21 @@ handle_nonnull_if_nonzero_attribute (tree *node, tree name, tree type = *node; tree pos = TREE_VALUE (args); tree pos2 = TREE_VALUE (TREE_CHAIN (args)); + tree chain2 = TREE_CHAIN (TREE_CHAIN (args)); + tree pos3 = NULL_TREE; + if (chain2) + pos3 = TREE_VALUE (chain2); tree val = positional_argument (type, name, pos, POINTER_TYPE, 1); tree val2 = positional_argument (type, name, pos2, INTEGER_TYPE, 2); - if (val && val2) + tree val3 = NULL_TREE; + if (chain2) + val3 = positional_argument (type, name, pos3, INTEGER_TYPE, 3); + if (val && val2 && (!chain2 || val3)) { TREE_VALUE (args) = val; TREE_VALUE (TREE_CHAIN (args)) = val2; + if (chain2) + TREE_VALUE (chain2) = val3; } else *no_add_attrs = true; @@ -5727,6 +5781,71 @@ handle_access_attribute (tree node[3], tree name, tree args, int flags, return NULL_TREE; } + +/* This function builds a string which is concatenated to SPEC and returns + list of variably bounds corresponding to an array/VLA parameter with + type TYPE. The string consists of one dollar symbol for each specified + variable bound, one asterisk for each unspecified variable bound, + a space for an array of unknown size (only possibly for the outermost), + and a zero for a zero-sized array. + + The chainof variable bounds starts with the most significant bound. + For example, the TYPE T[2][m][3][n] will produce "$$" and (m, (n, nil)). */ + +static tree +build_arg_spec (tree type, std::string *spec) +{ + while (POINTER_TYPE_P (type)) + type = TREE_TYPE (type); + + if (TREE_CODE (type) != ARRAY_TYPE) + return NULL_TREE; + + tree list = build_arg_spec (TREE_TYPE (type), spec); + + if (!COMPLETE_TYPE_P (type)) + { + (*spec) += ' '; + return list; + } + + tree mval = TYPE_MAX_VALUE (TYPE_DOMAIN (type)); + + if (!mval) + { + (*spec) += '0'; + return list; + } + + if (TREE_CODE (mval) == COMPOUND_EXPR + && integer_zerop (TREE_OPERAND (mval, 0)) + && integer_zerop (TREE_OPERAND (mval, 1))) + { + (*spec) += '*'; + return list; + } + + if (TREE_CODE (mval) == INTEGER_CST) + return list; + + /* A variable bound. */ + (*spec) += '$'; + + mval = array_type_nelts_top (type); + + /* Remove NOP_EXPR and SAVE_EXPR to uncover possible PARM_DECLS. */ + if (TREE_CODE (mval) == NOP_EXPR) + mval = TREE_OPERAND (mval, 0); + if (TREE_CODE (mval) == SAVE_EXPR) + { + mval = TREE_OPERAND (mval, 0); + if (TREE_CODE (mval) == NOP_EXPR) + mval = TREE_OPERAND (mval, 0); + } + + return tree_cons (NULL_TREE, mval, list); +} + /* Extract attribute "arg spec" from each FNDECL argument that has it, build a single attribute access corresponding to all the arguments, and return the result. SKIP_VOIDPTR set to ignore void* parameters @@ -5803,15 +5922,16 @@ build_attr_access_from_parms (tree parms, bool skip_voidptr) argspec = TREE_VALUE (argspec); /* The attribute arg spec string. */ - tree str = TREE_VALUE (argspec); - const char *s = TREE_STRING_POINTER (str); + const char *s = TREE_STRING_POINTER (TREE_VALUE (argspec)); + bool static_p = s && (0 == strcmp("static", s)); /* Collect the list of nonnull arguments which use "[static ..]". */ - if (s != NULL && s[0] == '[' && s[1] == 's') + if (static_p) nnlist = tree_cons (NULL_TREE, build_int_cst (integer_type_node, argpos + 1), nnlist); - /* Create the attribute access string from the arg spec string, + tree argvbs; + /* Create the attribute access string from the arg spec data, optionally followed by position of the VLA bound argument if it is one. */ { @@ -5822,21 +5942,52 @@ build_attr_access_from_parms (tree parms, bool skip_voidptr) specend = 1; } - /* Format the access string in place. */ - int len = snprintf (NULL, 0, "%c%u%s", - attr_access::mode_chars[access_deferred], - argpos, s); - spec.resize (specend + len + 1); - sprintf (&spec[specend], "%c%u%s", - attr_access::mode_chars[access_deferred], - argpos, s); + spec += attr_access::mode_chars[access_deferred]; + spec += std::to_string (argpos); + spec += '['; + tree type = TREE_VALUE (TREE_CHAIN (argspec)); + argvbs = build_arg_spec (type, &spec); + + /* Postprocess the string to bring it in the format expected + by the code handling the access attribute. First, we + add 's' if the array was declared as [static ...]. */ + if (static_p) + { + size_t send = spec.length(); + + if (spec[send - 1] == '[') + { + spec += 's'; + } + else + { + /* If there is a symbol, we need to swap the order. */ + spec += spec[send - 1]; + spec[send - 1] = 's'; + } + } + + /* If the outermost bound is an integer constant, we need to write + the size if it is constant. */ + if (type && TYPE_DOMAIN (type)) + { + tree mval = TYPE_MAX_VALUE (TYPE_DOMAIN (type)); + if (mval && TREE_CODE (mval) == INTEGER_CST) + { + char buf[40]; + unsigned HOST_WIDE_INT n = tree_to_uhwi (mval) + 1; + sprintf (buf, HOST_WIDE_INT_PRINT_UNSIGNED, n); + spec += buf; + } + } + spec += ']'; + /* Trim the trailing NUL. */ - spec.resize (specend + len); + spec.resize (spec.length ()); } /* The (optional) list of expressions denoting the VLA bounds N in ARGTYPE <arg>[Ni]...[Nj]...[Nk]. */ - tree argvbs = TREE_CHAIN (argspec); if (argvbs) { spec += ','; @@ -5849,8 +6000,7 @@ build_attr_access_from_parms (tree parms, bool skip_voidptr) order. */ vblist = tree_cons (NULL_TREE, argvbs, vblist); - unsigned nelts = 0; - for (tree vb = argvbs; vb; vb = TREE_CHAIN (vb), ++nelts) + for (tree vb = argvbs; vb; vb = TREE_CHAIN (vb)) { tree bound = TREE_VALUE (vb); if (const unsigned *psizpos = arg2pos.get (bound)) @@ -6132,7 +6282,9 @@ handle_target_clones_attribute (tree *node, tree name, tree ARG_UNUSED (args), } } - if (get_target_clone_attr_len (args) == -1) + auto_vec<string_slice> versions = get_clone_attr_versions (args, NULL); + + if (versions.length () == 1) { warning (OPT_Wattributes, "single %<target_clones%> attribute is ignored"); diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc index 587d764..e7dd460 100644 --- a/gcc/c-family/c-common.cc +++ b/gcc/c-family/c-common.cc @@ -56,6 +56,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-pretty-print-markup.h" #include "gcc-rich-location.h" #include "gcc-urlifier.h" +#include "diagnostics/diagnostics-selftests.h" cpp_reader *parse_in; /* Declared in c-pragma.h. */ @@ -394,6 +395,7 @@ const struct c_common_resword c_common_reswords[] = { { "_Alignas", RID_ALIGNAS, D_CONLY }, { "_Alignof", RID_ALIGNOF, D_CONLY }, + { "_Countof", RID_COUNTOF, D_CONLY }, { "_Atomic", RID_ATOMIC, D_CONLY }, { "_BitInt", RID_BITINT, D_CONLY }, { "_Bool", RID_BOOL, D_CONLY }, @@ -3437,20 +3439,41 @@ pointer_int_sum (location_t loc, enum tree_code resultcode, an overflow error if the constant is negative but INTOP is not. */ && (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (intop)) || (TYPE_PRECISION (TREE_TYPE (intop)) - == TYPE_PRECISION (TREE_TYPE (ptrop))))) - { - enum tree_code subcode = resultcode; - tree int_type = TREE_TYPE (intop); - if (TREE_CODE (intop) == MINUS_EXPR) - subcode = (subcode == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR); - /* Convert both subexpression types to the type of intop, - because weird cases involving pointer arithmetic - can result in a sum or difference with different type args. */ - ptrop = build_binary_op (EXPR_LOCATION (TREE_OPERAND (intop, 1)), - subcode, ptrop, - convert (int_type, TREE_OPERAND (intop, 1)), - true); - intop = convert (int_type, TREE_OPERAND (intop, 0)); + == TYPE_PRECISION (TREE_TYPE (ptrop)))) + && TYPE_PRECISION (TREE_TYPE (intop)) <= TYPE_PRECISION (sizetype)) + { + tree intop0 = TREE_OPERAND (intop, 0); + tree intop1 = TREE_OPERAND (intop, 1); + if (TYPE_PRECISION (TREE_TYPE (intop)) != TYPE_PRECISION (sizetype) + || TYPE_UNSIGNED (TREE_TYPE (intop)) != TYPE_UNSIGNED (sizetype)) + { + tree optype = c_common_type_for_size (TYPE_PRECISION (sizetype), + TYPE_UNSIGNED (sizetype)); + intop0 = convert (optype, intop0); + intop1 = convert (optype, intop1); + } + tree t = fold_build2_loc (loc, MULT_EXPR, TREE_TYPE (intop0), intop0, + convert (TREE_TYPE (intop0), size_exp)); + intop0 = convert (sizetype, t); + if (TREE_OVERFLOW_P (intop0) && !TREE_OVERFLOW (t)) + intop0 = wide_int_to_tree (TREE_TYPE (intop0), wi::to_wide (intop0)); + t = fold_build2_loc (loc, MULT_EXPR, TREE_TYPE (intop1), intop1, + convert (TREE_TYPE (intop1), size_exp)); + intop1 = convert (sizetype, t); + if (TREE_OVERFLOW_P (intop1) && !TREE_OVERFLOW (t)) + intop1 = wide_int_to_tree (TREE_TYPE (intop1), wi::to_wide (intop1)); + intop = build_binary_op (EXPR_LOCATION (intop), TREE_CODE (intop), + intop0, intop1, true); + + /* Create the sum or difference. */ + if (resultcode == MINUS_EXPR) + intop = fold_build1_loc (loc, NEGATE_EXPR, sizetype, intop); + + ret = fold_build_pointer_plus_loc (loc, ptrop, intop); + + fold_undefer_and_ignore_overflow_warnings (); + + return ret; } /* Convert the integer argument to a type the same size as sizetype @@ -4080,6 +4103,31 @@ c_alignof_expr (location_t loc, tree expr) return fold_convert_loc (loc, size_type_node, t); } + +/* Implement the _Countof keyword: + Return the number of elements of an array. */ + +tree +c_countof_type (location_t loc, tree type) +{ + enum tree_code type_code; + + type_code = TREE_CODE (type); + if (type_code != ARRAY_TYPE) + { + error_at (loc, "invalid application of %<_Countof%> to type %qT", type); + return error_mark_node; + } + if (!COMPLETE_TYPE_P (type)) + { + error_at (loc, + "invalid application of %<_Countof%> to incomplete type %qT", + type); + return error_mark_node; + } + + return array_type_nelts_top (type); +} /* Handle C and C++ default attributes. */ @@ -5723,8 +5771,8 @@ struct nonnull_arg_ctx /* The function whose arguments are being checked and its type (used for calls through function pointers). */ const_tree fndecl, fntype; - /* For nonnull_if_nonzero, index of the other argument. */ - unsigned HOST_WIDE_INT other; + /* For nonnull_if_nonzero, index of the other arguments. */ + unsigned HOST_WIDE_INT other1, other2; /* True if a warning has been issued. */ bool warned_p; }; @@ -5792,6 +5840,7 @@ check_function_nonnull (nonnull_arg_ctx &ctx, int nargs, tree *argarray) check_function_arguments_recurse (check_nonnull_arg, &ctx, argarray[i], i + 1, OPT_Wnonnull); + a = NULL_TREE; } } if (a == NULL_TREE) @@ -5803,17 +5852,25 @@ check_function_nonnull (nonnull_arg_ctx &ctx, int nargs, tree *argarray) unsigned int idx = TREE_INT_CST_LOW (TREE_VALUE (args)) - 1; unsigned int idx2 = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (args))) - 1; + unsigned int idx3 = idx2; + if (tree chain2 = TREE_CHAIN (TREE_CHAIN (args))) + idx3 = TREE_INT_CST_LOW (TREE_VALUE (chain2)) - 1; if (idx < (unsigned) nargs - firstarg && idx2 < (unsigned) nargs - firstarg + && idx3 < (unsigned) nargs - firstarg && INTEGRAL_TYPE_P (TREE_TYPE (argarray[firstarg + idx2])) - && integer_nonzerop (argarray[firstarg + idx2])) + && integer_nonzerop (argarray[firstarg + idx2]) + && INTEGRAL_TYPE_P (TREE_TYPE (argarray[firstarg + idx3])) + && integer_nonzerop (argarray[firstarg + idx3])) { - ctx.other = firstarg + idx2 + 1; + ctx.other1 = firstarg + idx2 + 1; + ctx.other2 = firstarg + idx3 + 1; check_function_arguments_recurse (check_nonnull_arg, &ctx, argarray[firstarg + idx], firstarg + idx + 1, OPT_Wnonnull); - ctx.other = 0; + ctx.other1 = 0; + ctx.other2 = 0; } } return ctx.warned_p; @@ -5997,14 +6054,25 @@ check_nonnull_arg (void *ctx, tree param, unsigned HOST_WIDE_INT param_num) } else { - if (pctx->other) + if (pctx->other1 && pctx->other2 != pctx->other1) + warned = warning_at (loc, OPT_Wnonnull, + "argument %u null where non-null expected " + "because arguments %u and %u are nonzero", + (unsigned) param_num, + TREE_CODE (pctx->fntype) == METHOD_TYPE + ? (unsigned) pctx->other1 - 1 + : (unsigned) pctx->other1, + TREE_CODE (pctx->fntype) == METHOD_TYPE + ? (unsigned) pctx->other2 - 1 + : (unsigned) pctx->other2); + else if (pctx->other1) warned = warning_at (loc, OPT_Wnonnull, "argument %u null where non-null expected " "because argument %u is nonzero", (unsigned) param_num, TREE_CODE (pctx->fntype) == METHOD_TYPE - ? (unsigned) pctx->other - 1 - : (unsigned) pctx->other); + ? (unsigned) pctx->other1 - 1 + : (unsigned) pctx->other1); else warned = warning_at (loc, OPT_Wnonnull, "argument %u null where non-null expected", @@ -6013,7 +6081,7 @@ check_nonnull_arg (void *ctx, tree param, unsigned HOST_WIDE_INT param_num) inform (DECL_SOURCE_LOCATION (pctx->fndecl), "in a call to function %qD declared %qs", pctx->fndecl, - pctx->other ? "nonnull_if_nonzero" : "nonnull"); + pctx->other1 ? "nonnull_if_nonzero" : "nonnull"); } if (warned) @@ -6269,7 +6337,7 @@ check_function_arguments (location_t loc, const_tree fndecl, const_tree fntype, to do this if format checking is enabled. */ if (warn_nonnull) { - nonnull_arg_ctx ctx = { loc, fndecl, fntype, 0, false }; + nonnull_arg_ctx ctx = { loc, fndecl, fntype, 0, 0, false }; warned_p = check_function_nonnull (ctx, nargs, argarray); } @@ -6958,7 +7026,7 @@ c_parse_error (const char *gmsgid, enum cpp_ttype token_type, /* Return the gcc option code associated with the reason for a cpp message, or 0 if none. */ -static diagnostic_option_id +static diagnostics::option_id c_option_controlling_cpp_diagnostic (enum cpp_warning_reason reason) { const struct cpp_reason_option_codes_t *entry; @@ -7000,8 +7068,8 @@ c_cpp_diagnostic (cpp_reader *pfile ATTRIBUTE_UNUSED, rich_location *richloc, const char *msg, va_list *ap) { - diagnostic_info diagnostic; - diagnostic_t dlevel; + diagnostics::diagnostic_info diagnostic; + enum diagnostics::kind dlevel; bool save_warn_system_headers = global_dc->m_warn_system_headers; bool ret; @@ -7015,24 +7083,24 @@ c_cpp_diagnostic (cpp_reader *pfile ATTRIBUTE_UNUSED, case CPP_DL_WARNING: if (flag_no_output) return false; - dlevel = DK_WARNING; + dlevel = diagnostics::kind::warning; break; case CPP_DL_PEDWARN: if (flag_no_output && !flag_pedantic_errors) return false; - dlevel = DK_PEDWARN; + dlevel = diagnostics::kind::pedwarn; break; case CPP_DL_ERROR: - dlevel = DK_ERROR; + dlevel = diagnostics::kind::error; break; case CPP_DL_ICE: - dlevel = DK_ICE; + dlevel = diagnostics::kind::ice; break; case CPP_DL_NOTE: - dlevel = DK_NOTE; + dlevel = diagnostics::kind::note; break; case CPP_DL_FATAL: - dlevel = DK_FATAL; + dlevel = diagnostics::kind::fatal; break; default: gcc_unreachable (); @@ -9896,8 +9964,11 @@ c_family_tests (void) c_indentation_cc_tests (); c_pretty_print_cc_tests (); c_spellcheck_cc_tests (); - c_diagnostic_cc_tests (); c_opt_problem_cc_tests (); + + /* According to https://gcc.gnu.org/pipermail/gcc/2021-November/237703.html + this has some language-specific assumptions, so we run it here. */ + diagnostics::selftest::context_cc_tests (); } } // namespace selftest @@ -9979,7 +10050,7 @@ try_to_locate_new_include_insertion_point (const char *file, location_t loc) return UNKNOWN_LOCATION; /* The "start_location" is column 0, meaning "the whole line". - rich_location and edit_context can't cope with this, so use + rich_location and diagnostics::changes can't cope with this, so use column 1 instead. */ location_t col_0 = ord_map_for_insertion->start_location; return linemap_position_for_loc_and_offset (line_table, col_0, 1); @@ -10043,7 +10114,7 @@ maybe_add_include_fixit (rich_location *richloc, const char *header, richloc->add_fixit_insert_before (include_insert_loc, text); free (text); - if (override_location && global_dc->m_source_printing.enabled) + if (override_location && global_dc->get_source_printing_options ().enabled) { /* Replace the primary location with that of the insertion point for the fix-it hint. diff --git a/gcc/c-family/c-common.def b/gcc/c-family/c-common.def index cf22282..0bcc499 100644 --- a/gcc/c-family/c-common.def +++ b/gcc/c-family/c-common.def @@ -50,6 +50,9 @@ DEFTREECODE (EXCESS_PRECISION_EXPR, "excess_precision_expr", tcc_expression, 1) number. */ DEFTREECODE (USERDEF_LITERAL, "userdef_literal", tcc_exceptional, 3) +/* Represents a 'countof' expression. */ +DEFTREECODE (COUNTOF_EXPR, "countof_expr", tcc_expression, 1) + /* Represents a 'sizeof' expression during C++ template expansion, or for the purpose of -Wsizeof-pointer-memaccess warning. */ DEFTREECODE (SIZEOF_EXPR, "sizeof_expr", tcc_expression, 1) diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index ea6c297..b6021d2 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -105,6 +105,7 @@ enum rid /* C extensions */ RID_ASM, RID_TYPEOF, RID_TYPEOF_UNQUAL, RID_ALIGNOF, RID_ATTRIBUTE, + RID_COUNTOF, RID_C23_VA_START, RID_VA_ARG, RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL, RID_CHOOSE_EXPR, RID_TYPES_COMPATIBLE_P, RID_BUILTIN_COMPLEX, RID_BUILTIN_SHUFFLE, @@ -746,7 +747,7 @@ enum cxx_dialect { cxx26 }; -/* The C++ dialect being used. C++98 is the default. */ +/* The C++ dialect being used. C++17 is the default. */ extern enum cxx_dialect cxx_dialect; /* Maximum template instantiation depth. This limit is rather @@ -890,6 +891,7 @@ extern tree c_common_truthvalue_conversion (location_t, tree); extern void c_apply_type_quals_to_decl (int, tree); extern tree c_sizeof_or_alignof_type (location_t, tree, bool, bool, int); extern tree c_alignof_expr (location_t, tree); +extern tree c_countof_type (location_t, tree); /* Print an error message for invalid operands to arith operation CODE. NOP_EXPR is used as a special case (see truthvalue_conversion). */ extern void binary_op_error (rich_location *, enum tree_code, tree, tree); @@ -977,7 +979,7 @@ extern tree build_va_arg (location_t, tree, tree); extern const unsigned int c_family_lang_mask; extern unsigned int c_common_option_lang_mask (void); -extern void c_common_diagnostics_set_defaults (diagnostic_context *); +extern void c_common_diagnostics_set_defaults (diagnostics::context *); extern bool c_common_complain_wrong_lang_p (const struct cl_option *); extern void c_common_init_options_struct (struct gcc_options *); extern void c_common_init_options (unsigned int, struct cl_decoded_option *); @@ -1263,7 +1265,7 @@ extern void c_stddef_cpp_builtins (void); extern void fe_file_change (const line_map_ordinary *); extern void c_parse_error (const char *, enum cpp_ttype, tree, unsigned char, rich_location *richloc); -extern diagnostic_option_id get_option_for_builtin_define (const char *macro_name); +extern diagnostics::option_id get_option_for_builtin_define (const char *macro_name); /* In c-ppoutput.cc */ extern void init_pp_output (FILE *); @@ -1301,10 +1303,12 @@ enum c_omp_region_type C_ORT_TARGET = 1 << 3, C_ORT_EXIT_DATA = 1 << 4, C_ORT_INTEROP = 1 << 5, + C_ORT_DECLARE_MAPPER = 1 << 6, C_ORT_OMP_DECLARE_SIMD = C_ORT_OMP | C_ORT_DECLARE_SIMD, C_ORT_OMP_TARGET = C_ORT_OMP | C_ORT_TARGET, C_ORT_OMP_EXIT_DATA = C_ORT_OMP | C_ORT_EXIT_DATA, C_ORT_OMP_INTEROP = C_ORT_OMP | C_ORT_INTEROP, + C_ORT_OMP_DECLARE_MAPPER = C_ORT_OMP | C_ORT_DECLARE_MAPPER, C_ORT_ACC_TARGET = C_ORT_ACC | C_ORT_TARGET }; @@ -1343,6 +1347,9 @@ extern enum omp_clause_defaultmap_kind c_omp_predetermined_mapping (tree); extern tree c_omp_check_context_selector (location_t, tree); extern void c_omp_mark_declare_variant (location_t, tree, tree); extern void c_omp_adjust_map_clauses (tree, bool); +template<typename T> struct omp_mapper_list; +extern void c_omp_find_nested_mappers (struct omp_mapper_list<tree> *, tree); +extern tree c_omp_instantiate_mappers (tree); namespace omp_addr_tokenizer { struct omp_addr_token; } typedef omp_addr_tokenizer::omp_addr_token omp_addr_token; @@ -1706,7 +1713,7 @@ 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); -extern void add_no_sanitize_value (tree node, unsigned int flags); +extern void add_no_sanitize_value (tree node, sanitize_code_type flags); extern void maybe_add_include_fixit (rich_location *, const char *, bool); extern void maybe_suggest_missing_token_insertion (rich_location *richloc, @@ -1722,7 +1729,6 @@ extern tree braced_lists_to_strings (tree, tree); namespace selftest { /* Declarations for specific families of tests within c-family, by source file, in alphabetical order. */ - extern void c_diagnostic_cc_tests (void); extern void c_format_cc_tests (void); extern void c_indentation_cc_tests (void); extern void c_opt_problem_cc_tests (void); diff --git a/gcc/c-family/c-cppbuiltin.cc b/gcc/c-family/c-cppbuiltin.cc index 4589ee4..6b22f9e 100644 --- a/gcc/c-family/c-cppbuiltin.cc +++ b/gcc/c-family/c-cppbuiltin.cc @@ -913,23 +913,42 @@ c_cpp_builtins (cpp_reader *pfile) /* encoding definitions used by users and libraries */ builtin_define_with_value ("__GNUC_EXECUTION_CHARSET_NAME", - cpp_get_narrow_charset_name (pfile), 1); + cpp_get_narrow_charset_name (pfile), 1); builtin_define_with_value ("__GNUC_WIDE_EXECUTION_CHARSET_NAME", - cpp_get_wide_charset_name (pfile), 1); - + cpp_get_wide_charset_name (pfile), 1); if (c_dialect_cxx ()) - { - int major; - parse_basever (&major, NULL, NULL); - cpp_define_formatted (pfile, "__GNUG__=%d", major); - } + { + int major; + parse_basever (&major, NULL, NULL); + cpp_define_formatted (pfile, "__GNUG__=%d", major); + } /* For stddef.h. They require macros defined in c-common.cc. */ c_stddef_cpp_builtins (); + /* Variant of cpp_define which arranges for diagnostics on user #define + or #undef of the macros. */ + auto cpp_define_warn = [] (cpp_reader *pfile, const char *def) + { + const char *end = strchr (def, '='); + cpp_define (pfile, def); + cpp_warn (pfile, def, end ? end - def : strlen (def)); + }; + if (c_dialect_cxx ()) { + /* Treat all cpp_define calls in this block for macros starting + with __cpp_ (for C++20 and later) or __STDCPP_ as cpp_define_warn. */ + auto cpp_define = [=] (cpp_reader *pfile, const char *def) + { + if ((cxx_dialect >= cxx20 && startswith (def, "__cpp_")) + || startswith (def, "__STDCPP_")) + cpp_define_warn (pfile, def); + else + ::cpp_define (pfile, def); + }; + if (flag_weak && SUPPORTS_ONE_ONLY) cpp_define (pfile, "__GXX_WEAK__=1"); else @@ -1087,52 +1106,79 @@ c_cpp_builtins (cpp_reader *pfile) { /* Set feature test macros for C++26. */ cpp_define (pfile, "__cpp_constexpr=202406L"); + cpp_define (pfile, "__cpp_constexpr_exceptions=202411L"); cpp_define (pfile, "__cpp_static_assert=202306L"); cpp_define (pfile, "__cpp_placeholder_variables=202306L"); - cpp_define (pfile, "__cpp_structured_bindings=202403L"); + cpp_define (pfile, "__cpp_structured_bindings=202411L"); cpp_define (pfile, "__cpp_deleted_function=202403L"); cpp_define (pfile, "__cpp_variadic_friend=202403L"); cpp_define (pfile, "__cpp_pack_indexing=202311L"); cpp_define (pfile, "__cpp_pp_embed=202502L"); + cpp_define (pfile, "__cpp_constexpr_virtual_inheritance=202506L"); + cpp_define (pfile, "__cpp_trivial_relocatability=202502L"); + cpp_define (pfile, "__cpp_expansion_statements=202506L"); } if (flag_concepts && cxx_dialect > cxx14) cpp_define (pfile, "__cpp_concepts=202002L"); + else if (cxx_dialect >= cxx20) + cpp_warn (pfile, "__cpp_concepts"); if (flag_contracts) { cpp_define (pfile, "__cpp_contracts=201906L"); cpp_define (pfile, "__cpp_contracts_literal_semantics=201906L"); cpp_define (pfile, "__cpp_contracts_roles=201906L"); } + else if (cxx_dialect >= cxx26) + cpp_warn (pfile, "__cpp_contracts"); if (flag_modules) /* The std-defined value is 201907L, but I don't think we can claim victory yet. 201810 is the p1103 date. */ cpp_define (pfile, "__cpp_modules=201810L"); + else if (cxx_dialect >= cxx20) + cpp_warn (pfile, "__cpp_modules"); if (flag_coroutines) cpp_define (pfile, "__cpp_impl_coroutine=201902L"); /* n4861, DIS */ + else if (cxx_dialect >= cxx20) + cpp_warn (pfile, "__cpp_impl_coroutine"); 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=201500L"); if (flag_sized_deallocation) cpp_define (pfile, "__cpp_sized_deallocation=201309L"); + else if (cxx_dialect >= cxx20) + cpp_warn (pfile, "__cpp_sized_deallocation"); if (aligned_new_threshold) { cpp_define (pfile, "__cpp_aligned_new=201606L"); cpp_define_formatted (pfile, "__STDCPP_DEFAULT_NEW_ALIGNMENT__=%d", aligned_new_threshold); } + else if (cxx_dialect >= cxx20) + cpp_warn (pfile, "__cpp_aligned_new"); + if (cxx_dialect >= cxx17) + cpp_warn (pfile, "__STDCPP_DEFAULT_NEW_ALIGNMENT__"); if (flag_new_ttp) cpp_define (pfile, "__cpp_template_template_args=201611L"); + else if (cxx_dialect >= cxx20) + cpp_warn (pfile, "__cpp_template_template_args"); if (flag_threadsafe_statics) cpp_define (pfile, "__cpp_threadsafe_static_init=200806L"); + else if (cxx_dialect >= cxx20) + cpp_warn (pfile, "__cpp_threadsafe_static_init"); if (flag_char8_t) cpp_define (pfile, "__cpp_char8_t=202207L"); + else if (cxx_dialect >= cxx20) + cpp_warn (pfile, "__cpp_char8_t"); #ifndef THREAD_MODEL_SPEC /* Targets that define THREAD_MODEL_SPEC need to define __STDCPP_THREADS__ in their config/XXX/XXX-c.c themselves. */ if (cxx_dialect >= cxx11 && strcmp (thread_model, "single") != 0) cpp_define (pfile, "__STDCPP_THREADS__=1"); + else #endif + if (cxx_dialect >= cxx11) + cpp_warn (pfile, "__STDCPP_THREADS__"); if (flag_implicit_constexpr) cpp_define (pfile, "__cpp_implicit_constexpr=20211111L"); } @@ -1281,16 +1327,22 @@ c_cpp_builtins (cpp_reader *pfile) for (int i = 0; i < NUM_FLOATN_NX_TYPES; i++) { - if (FLOATN_NX_TYPE_NODE (i) == NULL_TREE) - continue; if (c_dialect_cxx () && cxx_dialect > cxx20 && !floatn_nx_types[i].extended) { char name[sizeof ("__STDCPP_FLOAT128_T__=1")]; + if (FLOATN_NX_TYPE_NODE (i) == NULL_TREE) + { + sprintf (name, "__STDCPP_FLOAT%d_T__", floatn_nx_types[i].n); + cpp_warn (pfile, name); + continue; + } sprintf (name, "__STDCPP_FLOAT%d_T__=1", floatn_nx_types[i].n); - cpp_define (pfile, name); + cpp_define_warn (pfile, name); } + else 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" : ""); @@ -1302,10 +1354,12 @@ c_cpp_builtins (cpp_reader *pfile) if (bfloat16_type_node) { if (c_dialect_cxx () && cxx_dialect > cxx20) - cpp_define (pfile, "__STDCPP_BFLOAT16_T__=1"); + cpp_define_warn (pfile, "__STDCPP_BFLOAT16_T__=1"); builtin_define_float_constants ("BFLT16", "BF16", "%s", "BF16", bfloat16_type_node); } + else if (cxx_dialect >= cxx23) + cpp_warn (pfile, "__STDCPP_BFLOAT16_T__"); /* For float.h. */ if (targetm.decimal_float_supported_p ()) @@ -1678,7 +1732,7 @@ c_cpp_builtins (cpp_reader *pfile) /* Given NAME, return the command-line option that would make it be a builtin define, or 0 if unrecognized. */ -diagnostic_option_id +diagnostics::option_id get_option_for_builtin_define (const char *name) { if (!strcmp (name, "_OPENACC")) diff --git a/gcc/c-family/c-format.cc b/gcc/c-family/c-format.cc index 211d20d..bf144d0 100644 --- a/gcc/c-family/c-format.cc +++ b/gcc/c-family/c-format.cc @@ -32,7 +32,8 @@ along with GCC; see the file COPYING3. If not see #include "diagnostic.h" #include "substring-locations.h" #include "selftest.h" -#include "selftest-diagnostic.h" +#include "diagnostics/selftest-context.h" +#include "diagnostics/file-cache.h" #include "builtins.h" #include "attribs.h" #include "c-family/c-type-mismatch.h" @@ -70,6 +71,7 @@ static GTY(()) tree local_event_ptr_node; static GTY(()) tree local_pp_element_ptr_node; static GTY(()) tree local_gimple_ptr_node; static GTY(()) tree local_cgraph_node_ptr_node; +static GTY(()) tree local_string_slice_node; static GTY(()) tree locus; static bool decode_format_attr (const_tree, tree, tree, function_format_info *, @@ -770,6 +772,7 @@ static const format_char_info asm_fprintf_char_table[] = { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "c", NULL }, \ { "r", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "//cR", NULL }, \ { "@", 1, STD_C89, { T_EVENT_PTR, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "\"", NULL }, \ + { "B", 1, STD_C89, { T_STRING_SLICE, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, \ { "e", 1, STD_C89, { T_PP_ELEMENT_PTR, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "\"", NULL }, \ { "<", 0, STD_C89, NOARGUMENTS, "", "<", NULL }, \ { ">", 0, STD_C89, NOARGUMENTS, "", ">", NULL }, \ @@ -2124,7 +2127,7 @@ flag_chars_t::validate (const format_kind_info *fki, { format_warning_at_char (format_string_loc, format_string_cst, format_chars - orig_format_chars - 1, - OPT_Wformat_, + OPT_Wformat_diag, "%s used within a quoted sequence", _(s->name)); } @@ -2137,7 +2140,7 @@ flag_chars_t::validate (const format_kind_info *fki, { format_warning_at_char (format_string_loc, format_string_cst, format_chars - orig_format_chars, - OPT_Wformat_, + OPT_Wformat_diag, "%qc conversion used unquoted", format_char); } @@ -4632,7 +4635,7 @@ get_corrected_substring (const substring_loc &fmt_loc, if (caret.column > finish.column) return NULL; - char_span line + diagnostics::char_span line = global_dc->get_file_cache ().get_source_line (start.file, start.line); if (!line) return NULL; @@ -4644,7 +4647,8 @@ get_corrected_substring (const substring_loc &fmt_loc, specification, up to the (but not including) the length modifier. In the above example, this would be "%-+*.*". */ int length_up_to_type = caret.column - start.column; - char_span prefix_span = line.subspan (start.column - 1, length_up_to_type); + diagnostics::char_span prefix_span + = line.subspan (start.column - 1, length_up_to_type); char *prefix = prefix_span.xstrdup (); /* Now attempt to generate a suggestion for the rest of the specification @@ -5211,6 +5215,11 @@ init_dynamic_diag_info (void) || local_cgraph_node_ptr_node == void_type_node) local_cgraph_node_ptr_node = get_named_type ("cgraph_node"); + /* Similar to the above but for string_slice*. */ + if (!local_string_slice_node + || local_string_slice_node == void_type_node) + local_string_slice_node = get_named_type ("string_slice"); + /* Similar to the above but for diagnostic_event_id_t*. */ if (!local_event_ptr_node || local_event_ptr_node == void_type_node) @@ -5577,10 +5586,12 @@ test_type_mismatch_range_labels () gcc_rich_location richloc (fmt, &fmt_label, nullptr); richloc.add_range (param, SHOW_RANGE_WITHOUT_CARET, ¶m_label); - test_diagnostic_context dc; + diagnostics::selftest::test_context dc; diagnostic_show_locus (&dc, - dc.m_source_printing, - &richloc, DK_ERROR, dc.get_reference_printer ()); + dc.get_source_printing_options (), + &richloc, + diagnostics::kind::error, + dc.get_reference_printer ()); if (c_dialect_cxx ()) /* "char*", without a space. */ ASSERT_STREQ (" printf (\"msg: %i\\n\", msg);\n" diff --git a/gcc/c-family/c-format.h b/gcc/c-family/c-format.h index 323338c..d44d386 100644 --- a/gcc/c-family/c-format.h +++ b/gcc/c-family/c-format.h @@ -317,6 +317,7 @@ struct format_kind_info #define T89_G { STD_C89, NULL, &local_gimple_ptr_node } #define T_CGRAPH_NODE { STD_C89, NULL, &local_cgraph_node_ptr_node } #define T_EVENT_PTR { STD_C89, NULL, &local_event_ptr_node } +#define T_STRING_SLICE { STD_C89, NULL, &local_string_slice_node } #define T_PP_ELEMENT_PTR { STD_C89, NULL, &local_pp_element_ptr_node } #define T89_T { STD_C89, NULL, &local_tree_type_node } #define T89_V { STD_C89, NULL, T_V } diff --git a/gcc/c-family/c-gimplify.cc b/gcc/c-family/c-gimplify.cc index c6fb764..131eca8 100644 --- a/gcc/c-family/c-gimplify.cc +++ b/gcc/c-family/c-gimplify.cc @@ -66,6 +66,19 @@ along with GCC; see the file COPYING3. If not see walk back up, we check that they fit our constraints, and copy them into temporaries if not. */ + +/* Check whether TP is an address computation whose base is a call to + .ACCESS_WITH_SIZE. */ + +static bool +is_address_with_access_with_size (tree tp) +{ + if (TREE_CODE (tp) == POINTER_PLUS_EXPR + && is_access_with_size_p (TREE_OPERAND (tp, 0))) + return true; + return false; +} + /* Callback for c_genericize. */ static tree @@ -121,6 +134,20 @@ ubsan_walk_array_refs_r (tree *tp, int *walk_subtrees, void *data) walk_tree (&TREE_OPERAND (*tp, 1), ubsan_walk_array_refs_r, pset, pset); walk_tree (&TREE_OPERAND (*tp, 0), ubsan_walk_array_refs_r, pset, pset); } + else if (TREE_CODE (*tp) == INDIRECT_REF + && is_address_with_access_with_size (TREE_OPERAND (*tp, 0))) + { + ubsan_maybe_instrument_array_ref (&TREE_OPERAND (*tp, 0), false); + /* Make sure ubsan_maybe_instrument_array_ref is not called again on + the POINTER_PLUS_EXPR, so ensure it is not walked again and walk + its subtrees manually. */ + tree aref = TREE_OPERAND (*tp, 0); + pset->add (aref); + *walk_subtrees = 0; + walk_tree (&TREE_OPERAND (aref, 0), ubsan_walk_array_refs_r, pset, pset); + } + else if (is_address_with_access_with_size (*tp)) + ubsan_maybe_instrument_array_ref (tp, true); return NULL_TREE; } diff --git a/gcc/c-family/c-indentation.cc b/gcc/c-family/c-indentation.cc index 2e8261d..d378464 100644 --- a/gcc/c-family/c-indentation.cc +++ b/gcc/c-family/c-indentation.cc @@ -25,6 +25,7 @@ along with GCC; see the file COPYING3. If not see #include "c-indentation.h" #include "selftest.h" #include "diagnostic.h" +#include "diagnostics/file-cache.h" /* Round up VIS_COLUMN to nearest tab stop. */ @@ -45,13 +46,13 @@ next_tab_stop (unsigned int vis_column, unsigned int tab_width) on the line (up to or before EXPLOC). */ static bool -get_visual_column (file_cache &fc, +get_visual_column (diagnostics::file_cache &fc, expanded_location exploc, unsigned int *out, unsigned int *first_nws, unsigned int tab_width) { - char_span line = fc.get_source_line (exploc.file, exploc.line); + diagnostics::char_span line = fc.get_source_line (exploc.file, exploc.line); if (!line) return false; if ((size_t)exploc.column > line.length ()) @@ -88,14 +89,14 @@ get_visual_column (file_cache &fc, Otherwise, return false, leaving *FIRST_NWS untouched. */ static bool -get_first_nws_vis_column (file_cache &fc, +get_first_nws_vis_column (diagnostics::file_cache &fc, const char *file, int line_num, unsigned int *first_nws, unsigned int tab_width) { gcc_assert (first_nws); - char_span line = fc.get_source_line (file, line_num); + diagnostics::char_span line = fc.get_source_line (file, line_num); if (!line) return false; unsigned int vis_column = 0; @@ -160,7 +161,7 @@ get_first_nws_vis_column (file_cache &fc, Return true if such an unindent/outdent is detected. */ static bool -detect_intervening_unindent (file_cache &fc, +detect_intervening_unindent (diagnostics::file_cache &fc, const char *file, int body_line, int next_stmt_line, @@ -329,13 +330,13 @@ should_warn_for_misleading_indentation (const token_indent_info &guard_tinfo, if (guard_loc == body_loc || body_loc == next_stmt_loc) return false; - const unsigned int tab_width = global_dc->m_tabstop; + const unsigned int tab_width = global_dc->get_column_options ().m_tabstop; /* They must be in the same file. */ if (next_stmt_exploc.file != body_exploc.file) return false; - file_cache &fc = global_dc->get_file_cache (); + diagnostics::file_cache &fc = global_dc->get_file_cache (); /* If NEXT_STMT_LOC and BODY_LOC are on the same line, consider the location of the guard. @@ -691,7 +692,7 @@ test_next_tab_stop () static void assert_get_visual_column_succeeds (const location &loc, - file_cache &fc, + diagnostics::file_cache &fc, const char *file, int line, int column, const unsigned int tab_width, unsigned int expected_visual_column, @@ -735,7 +736,7 @@ assert_get_visual_column_succeeds (const location &loc, static void assert_get_visual_column_fails (const location &loc, - file_cache &fc, + diagnostics::file_cache &fc, const char *file, int line, int column, const unsigned int tab_width) { @@ -783,7 +784,7 @@ test_get_visual_column () "\t line 2\n"); line_table_test ltt; temp_source_file tmp (SELFTEST_LOCATION, ".txt", content); - file_cache fc; + diagnostics::file_cache fc; const unsigned int tab_width = 8; const char *file = tmp.get_filename (); diff --git a/gcc/c-family/c-lex.cc b/gcc/c-family/c-lex.cc index fef6ae6..b45d722 100644 --- a/gcc/c-family/c-lex.cc +++ b/gcc/c-family/c-lex.cc @@ -1176,7 +1176,7 @@ interpret_integer (const cpp_token *token, unsigned int flags, && (flags & CPP_N_WIDTH) != CPP_N_LARGE) emit_diagnostic ((c_dialect_cxx () ? cxx_dialect == cxx98 : !flag_isoc99) - ? DK_PEDWARN : DK_WARNING, + ? diagnostics::kind::pedwarn : diagnostics::kind::warning, input_location, OPT_Wlong_long, (flags & CPP_N_UNSIGNED) ? "integer constant is too large for %<unsigned long%> type" diff --git a/gcc/c-family/c-omp.cc b/gcc/c-family/c-omp.cc index a92c6e3..fe272888 100644 --- a/gcc/c-family/c-omp.cc +++ b/gcc/c-family/c-omp.cc @@ -52,8 +52,8 @@ 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 (omp_find_clause (clauses, OMP_CLAUSE_ASYNC)) - t = OMP_CLAUSE_ASYNC_EXPR (clauses); + if ((t = omp_find_clause (clauses, OMP_CLAUSE_ASYNC))) + t = OMP_CLAUSE_ASYNC_EXPR (t); else t = build_int_cst (integer_type_node, GOMP_ASYNC_SYNC); @@ -71,6 +71,11 @@ c_finish_oacc_wait (location_t loc, tree parms, tree clauses) stmt = build_call_expr_loc_vec (loc, stmt, args); + t = omp_find_clause (clauses, OMP_CLAUSE_IF); + if (t) + stmt = build3_loc (input_location, COND_EXPR, void_type_node, + OMP_CLAUSE_IF_EXPR (t), stmt, NULL_TREE); + vec_free (args); return stmt; @@ -764,9 +769,7 @@ c_finish_omp_depobj (location_t loc, tree depobj, kind = OMP_CLAUSE_DEPEND_KIND (clause); t = OMP_CLAUSE_DECL (clause); gcc_assert (t); - if (TREE_CODE (t) == TREE_LIST - && TREE_PURPOSE (t) - && TREE_CODE (TREE_PURPOSE (t)) == TREE_VEC) + if (OMP_ITERATOR_DECL_P (t)) { error_at (OMP_CLAUSE_LOCATION (clause), "%<iterator%> modifier may not be specified on " @@ -4282,6 +4285,306 @@ c_omp_address_inspector::expand_map_clause (tree c, tree expr, return error_mark_node; } +/* Given a mapper function MAPPER_FN, recursively scan through the map clauses + for that mapper, and if any of those should use a (named or unnamed) mapper + themselves, add it to MLIST. */ + +void +c_omp_find_nested_mappers (omp_mapper_list<tree> *mlist, tree mapper_fn) +{ + tree mapper = lang_hooks.decls.omp_extract_mapper_directive (mapper_fn); + tree mapper_name = NULL_TREE; + + if (mapper == error_mark_node) + return; + + gcc_assert (TREE_CODE (mapper) == OMP_DECLARE_MAPPER); + + for (tree clause = OMP_DECLARE_MAPPER_CLAUSES (mapper); + clause; + clause = OMP_CLAUSE_CHAIN (clause)) + { + tree expr = OMP_CLAUSE_DECL (clause); + enum gomp_map_kind clause_kind = OMP_CLAUSE_MAP_KIND (clause); + tree elem_type; + + if (clause_kind == GOMP_MAP_PUSH_MAPPER_NAME) + { + mapper_name = expr; + continue; + } + else if (clause_kind == GOMP_MAP_POP_MAPPER_NAME) + { + mapper_name = NULL_TREE; + continue; + } + + gcc_assert (TREE_CODE (expr) != TREE_LIST); + if (TREE_CODE (expr) == OMP_ARRAY_SECTION) + { + while (TREE_CODE (expr) == OMP_ARRAY_SECTION) + expr = TREE_OPERAND (expr, 0); + + elem_type = TREE_TYPE (expr); + } + else + elem_type = TREE_TYPE (expr); + + /* This might be too much... or not enough? */ + while (TREE_CODE (elem_type) == ARRAY_TYPE + || TREE_CODE (elem_type) == POINTER_TYPE + || TREE_CODE (elem_type) == REFERENCE_TYPE) + elem_type = TREE_TYPE (elem_type); + + elem_type = TYPE_MAIN_VARIANT (elem_type); + + if (RECORD_OR_UNION_TYPE_P (elem_type) + && !mlist->contains (mapper_name, elem_type)) + { + tree nested_mapper_fn + = lang_hooks.decls.omp_mapper_lookup (mapper_name, elem_type); + + if (nested_mapper_fn) + { + mlist->add_mapper (mapper_name, elem_type, nested_mapper_fn); + c_omp_find_nested_mappers (mlist, nested_mapper_fn); + } + else if (mapper_name) + { + error ("mapper %qE not found for type %qT", mapper_name, + elem_type); + continue; + } + } + } +} + +struct remap_mapper_decl_info +{ + tree dummy_var; + tree expr; +}; + +/* Helper for rewriting DUMMY_VAR into EXPR in a map clause decl. */ + +static tree +remap_mapper_decl_1 (tree *tp, int *walk_subtrees, void *data) +{ + remap_mapper_decl_info *map_info = (remap_mapper_decl_info *) data; + + if (operand_equal_p (*tp, map_info->dummy_var)) + { + *tp = map_info->expr; + *walk_subtrees = 0; + } + + return NULL_TREE; +} + +/* Instantiate a mapper MAPPER for expression EXPR, adding new clauses to + OUTLIST. OUTER_KIND is the mapping kind to use if not already specified in + the mapper declaration. */ + +static tree * +omp_instantiate_mapper (tree *outlist, tree mapper, tree expr, + enum gomp_map_kind outer_kind) +{ + tree clauses = OMP_DECLARE_MAPPER_CLAUSES (mapper); + tree dummy_var = OMP_DECLARE_MAPPER_DECL (mapper); + tree mapper_name = NULL_TREE; + + remap_mapper_decl_info map_info; + map_info.dummy_var = dummy_var; + map_info.expr = expr; + + for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) + { + tree unshared = unshare_expr (c); + enum gomp_map_kind clause_kind = OMP_CLAUSE_MAP_KIND (c); + tree t = OMP_CLAUSE_DECL (unshared); + tree type = NULL_TREE; + bool nonunit_array_with_mapper = false; + + if (clause_kind == GOMP_MAP_PUSH_MAPPER_NAME) + { + mapper_name = t; + continue; + } + else if (clause_kind == GOMP_MAP_POP_MAPPER_NAME) + { + mapper_name = NULL_TREE; + continue; + } + + if (TREE_CODE (t) == OMP_ARRAY_SECTION) + { + location_t loc = OMP_CLAUSE_LOCATION (c); + tree t2 = lang_hooks.decls.omp_map_array_section (loc, t); + + if (t2 == t) + { + nonunit_array_with_mapper = true; + /* We'd want use the mapper for the element type if this worked: + look that one up. */ + type = TREE_TYPE (TREE_TYPE (t)); + } + else + { + t = t2; + type = TREE_TYPE (t); + } + } + else + type = TREE_TYPE (t); + + gcc_assert (type); + + if (type == error_mark_node) + continue; + + walk_tree (&unshared, remap_mapper_decl_1, &map_info, NULL); + + if (OMP_CLAUSE_MAP_KIND (unshared) == GOMP_MAP_UNSET) + OMP_CLAUSE_SET_MAP_KIND (unshared, outer_kind); + + type = TYPE_MAIN_VARIANT (type); + + tree mapper_fn = lang_hooks.decls.omp_mapper_lookup (mapper_name, type); + + if (mapper_fn && nonunit_array_with_mapper) + { + sorry ("user-defined mapper with non-unit length array section"); + continue; + } + else if (mapper_fn) + { + tree nested_mapper + = lang_hooks.decls.omp_extract_mapper_directive (mapper_fn); + if (nested_mapper != mapper) + { + if (clause_kind == GOMP_MAP_UNSET) + clause_kind = outer_kind; + + outlist = omp_instantiate_mapper (outlist, nested_mapper, + t, clause_kind); + continue; + } + } + else if (mapper_name) + { + error ("mapper %qE not found for type %qT", mapper_name, type); + continue; + } + + *outlist = unshared; + outlist = &OMP_CLAUSE_CHAIN (unshared); + } + + return outlist; +} + +/* Given a list of CLAUSES, scan each clause and invoke a user-defined mapper + appropriate to the type of the data in that clause, if such a mapper is + visible in the current parsing context. */ + +tree +c_omp_instantiate_mappers (tree clauses) +{ + tree c, *pc, mapper_name = NULL_TREE; + + for (pc = &clauses, c = clauses; c; c = *pc) + { + bool using_mapper = false; + + switch (OMP_CLAUSE_CODE (c)) + { + case OMP_CLAUSE_MAP: + { + tree t = OMP_CLAUSE_DECL (c); + tree type = NULL_TREE; + bool nonunit_array_with_mapper = false; + + if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_PUSH_MAPPER_NAME + || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POP_MAPPER_NAME) + { + if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_PUSH_MAPPER_NAME) + mapper_name = OMP_CLAUSE_DECL (c); + else + mapper_name = NULL_TREE; + pc = &OMP_CLAUSE_CHAIN (c); + continue; + } + + if (TREE_CODE (t) == OMP_ARRAY_SECTION) + { + location_t loc = OMP_CLAUSE_LOCATION (c); + tree t2 = lang_hooks.decls.omp_map_array_section (loc, t); + + if (t2 == t) + { + /* !!! Array sections of size >1 with mappers for elements + are hard to support. Do something here. */ + nonunit_array_with_mapper = true; + type = TREE_TYPE (TREE_TYPE (t)); + } + else + { + t = t2; + type = TREE_TYPE (t); + } + } + else + type = TREE_TYPE (t); + + if (type == NULL_TREE || type == error_mark_node) + { + pc = &OMP_CLAUSE_CHAIN (c); + continue; + } + + enum gomp_map_kind kind = OMP_CLAUSE_MAP_KIND (c); + if (kind == GOMP_MAP_UNSET) + kind = GOMP_MAP_TOFROM; + + type = TYPE_MAIN_VARIANT (type); + + tree mapper_fn + = lang_hooks.decls.omp_mapper_lookup (mapper_name, type); + + if (mapper_fn && nonunit_array_with_mapper) + { + sorry ("user-defined mapper with non-unit length " + "array section"); + using_mapper = true; + } + else if (mapper_fn) + { + tree mapper + = lang_hooks.decls.omp_extract_mapper_directive (mapper_fn); + pc = omp_instantiate_mapper (pc, mapper, t, kind); + using_mapper = true; + } + else if (mapper_name) + { + error ("mapper %qE not found for type %qT", mapper_name, type); + using_mapper = true; + } + } + break; + + default: + ; + } + + if (using_mapper) + *pc = OMP_CLAUSE_CHAIN (c); + else + pc = &OMP_CLAUSE_CHAIN (c); + } + + return clauses; +} + const struct c_omp_directive c_omp_directives[] = { /* Keep this alphabetically sorted by the first word. Non-null second/third if any should precede null ones. */ diff --git a/gcc/c-family/c-opts.cc b/gcc/c-family/c-opts.cc index 4016382..0ec30e8 100644 --- a/gcc/c-family/c-opts.cc +++ b/gcc/c-family/c-opts.cc @@ -32,7 +32,7 @@ along with GCC; see the file COPYING3. If not see #include "flags.h" #include "toplev.h" #include "langhooks.h" -#include "diagnostic-macro-unwinding.h" /* for virt_loc_aware_diagnostic_finalizer */ +#include "diagnostics/macro-unwinding.h" /* for virt_loc_aware_diagnostic_finalizer */ #include "intl.h" #include "cppdefault.h" #include "incpath.h" @@ -43,7 +43,7 @@ along with GCC; see the file COPYING3. If not see #include "dumpfile.h" #include "file-prefix-map.h" /* add_*_prefix_map() */ #include "context.h" -#include "diagnostic-format-text.h" +#include "diagnostics/text-sink.h" #ifndef DOLLARS_IN_IDENTIFIERS # define DOLLARS_IN_IDENTIFIERS true @@ -169,9 +169,9 @@ c_common_option_lang_mask (void) /* Diagnostic finalizer for C/C++/Objective-C/Objective-C++. */ static void -c_diagnostic_text_finalizer (diagnostic_text_output_format &text_output, - const diagnostic_info *diagnostic, - diagnostic_t) +c_diagnostic_text_finalizer (diagnostics::text_sink &text_output, + const diagnostics::diagnostic_info *diagnostic, + enum diagnostics::kind) { pretty_printer *const pp = text_output.get_printer (); char *saved_prefix = pp_take_prefix (pp); @@ -179,20 +179,20 @@ c_diagnostic_text_finalizer (diagnostic_text_output_format &text_output, pp_newline (pp); diagnostic_show_locus (&text_output.get_context (), text_output.get_source_printing_options (), - diagnostic->richloc, diagnostic->kind, pp); + diagnostic->m_richloc, diagnostic->m_kind, pp); /* By default print macro expansion contexts in the diagnostic finalizer -- for tokens resulting from macro expansion. */ - virt_loc_aware_diagnostic_finalizer (text_output, diagnostic); + diagnostics::virt_loc_aware_text_finalizer (text_output, diagnostic); pp_set_prefix (pp, saved_prefix); pp_flush (pp); } /* Common default settings for diagnostics. */ void -c_common_diagnostics_set_defaults (diagnostic_context *context) +c_common_diagnostics_set_defaults (diagnostics::context *context) { - diagnostic_text_finalizer (context) = c_diagnostic_text_finalizer; - context->m_opt_permissive = OPT_fpermissive; + diagnostics::text_finalizer (context) = c_diagnostic_text_finalizer; + context->set_permissive_option (OPT_fpermissive); } /* Input charset configuration for diagnostics. */ @@ -278,7 +278,7 @@ c_common_init_options (unsigned int decoded_options_count, if (c_dialect_cxx ()) set_std_cxx17 (/*ISO*/false); - global_dc->m_source_printing.colorize_source_p = true; + global_dc->get_source_printing_options ().colorize_source_p = true; } /* Handle switch SCODE with argument ARG. VALUE is true, unless no- @@ -959,6 +959,15 @@ c_common_post_options (const char **pfilename) if (warn_enum_compare == -1) warn_enum_compare = c_dialect_cxx () ? 1 : 0; + /* For C++26 default to -Wkeyword-macro if -Wpedantic. */ + if (cxx_dialect >= cxx26 && pedantic) + { + SET_OPTION_IF_UNSET (&global_options, &global_options_set, + warn_keyword_macro, 1); + if (warn_keyword_macro) + cpp_opts->cpp_warn_keyword_macro = warn_keyword_macro; + } + /* -Wpacked-bitfield-compat is on by default for the C languages. The warning is issued in stor-layout.cc which is not part of the front-end so we need to selectively turn it on here. */ @@ -1085,12 +1094,21 @@ c_common_post_options (const char **pfilename) /* Change flag_abi_version to be the actual current ABI level, for the benefit of c_cpp_builtins, and to make comparison simpler. */ const int latest_abi_version = 21; + /* Possibly different for non-default ABI fixes within a release. */ + const int default_abi_version = latest_abi_version; /* Generate compatibility aliases for ABI v18 (GCC 13) by default. */ const int abi_compat_default = 18; + if (flag_abi_version > latest_abi_version) + warning (0, "%<-fabi-version=%d%> is not supported, using =%d", + flag_abi_version, latest_abi_version); + + SET_OPTION_IF_UNSET (&global_options, &global_options_set, + flag_abi_version, default_abi_version); + #define clamp(X) if (X == 0 || X > latest_abi_version) X = latest_abi_version clamp (flag_abi_version); - clamp (warn_abi_version); + /* Don't clamp warn_abi_version, let it be 0 or out of bounds. */ clamp (flag_abi_compat_version); #undef clamp @@ -1101,24 +1119,17 @@ c_common_post_options (const char **pfilename) flag_abi_compat_version = warn_abi_version; else if (warn_abi_version == -1 && flag_abi_compat_version == -1) { - warn_abi_version = latest_abi_version; - if (flag_abi_version == latest_abi_version) - { - auto_diagnostic_group d; - if (warning (OPT_Wabi, "%<-Wabi%> won%'t warn about anything")) - { - inform (input_location, "%<-Wabi%> warns about differences " - "from the most up-to-date ABI, which is also used " - "by default"); - inform (input_location, "use e.g. %<-Wabi=11%> to warn about " - "changes from GCC 7"); - } - flag_abi_compat_version = abi_compat_default; - } + warn_abi_version = 0; + if (flag_abi_version == default_abi_version) + flag_abi_compat_version = abi_compat_default; else flag_abi_compat_version = latest_abi_version; } + /* Allow warnings vs ABI versions beyond what we currently support. */ + if (warn_abi_version == 0) + warn_abi_version = 1000; + /* 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. */ @@ -1163,6 +1174,9 @@ c_common_post_options (const char **pfilename) warn_cxx20_compat = 0; cpp_opts->cpp_warn_cxx20_compat = 0; } + if (cxx_dialect >= cxx26) + /* Don't warn about C++26 compatibility changes in C++26 or later. */ + warn_cxx26_compat = 0; /* C++17 has stricter evaluation order requirements; let's use some of them for earlier C++ as well, so chaining works as expected. */ @@ -1186,7 +1200,7 @@ c_common_post_options (const char **pfilename) flag_char8_t = (cxx_dialect >= cxx20) || flag_isoc23; cpp_opts->unsigned_utf8char = flag_char8_t ? 1 : cpp_opts->unsigned_char; - cpp_opts->cpp_tabstop = global_dc->m_tabstop; + cpp_opts->cpp_tabstop = global_dc->get_column_options ().m_tabstop; if (flag_extern_tls_init) { @@ -1213,10 +1227,25 @@ c_common_post_options (const char **pfilename) if (cxx_dialect >= cxx20) flag_concepts = 1; + /* Coroutines are also a C++20 feature. */ + SET_OPTION_IF_UNSET (&global_options, &global_options_set, + flag_coroutines, cxx_dialect >= cxx20); + /* Enable lifetime extension of range based for temporaries for C++23. */ SET_OPTION_IF_UNSET (&global_options, &global_options_set, flag_range_for_ext_temps, cxx_dialect >= cxx23); + /* EnabledBy unfortunately can't specify value to use if set and + LangEnabledBy can't specify multiple options with &&. For -Wunused + or -Wunused -Wextra we want these to default to 3 unless user specified + some other level explicitly. */ + if (warn_unused_but_set_parameter == 1) + SET_OPTION_IF_UNSET (&global_options, &global_options_set, + warn_unused_but_set_parameter, 3); + if (warn_unused_but_set_variable == 1) + SET_OPTION_IF_UNSET (&global_options, &global_options_set, + warn_unused_but_set_variable, 3); + /* -fimmediate-escalation has no effect when immediate functions are not supported. */ if (flag_immediate_escalation && cxx_dialect < cxx20) @@ -2007,8 +2036,6 @@ set_std_cxx20 (int iso) flag_isoc94 = 1; flag_isoc99 = 1; flag_isoc11 = 1; - /* C++20 includes coroutines. */ - flag_coroutines = true; cxx_dialect = cxx20; lang_hooks.name = "GNU C++20"; } @@ -2025,8 +2052,6 @@ set_std_cxx23 (int iso) flag_isoc94 = 1; flag_isoc99 = 1; flag_isoc11 = 1; - /* C++23 includes coroutines. */ - flag_coroutines = true; cxx_dialect = cxx23; lang_hooks.name = "GNU C++23"; } @@ -2043,8 +2068,6 @@ set_std_cxx26 (int iso) flag_isoc94 = 1; flag_isoc99 = 1; flag_isoc11 = 1; - /* C++26 includes coroutines. */ - flag_coroutines = true; cxx_dialect = cxx26; lang_hooks.name = "GNU C++26"; } diff --git a/gcc/c-family/c-pragma.cc b/gcc/c-family/c-pragma.cc index 8b5cdcc..8a1218b 100644 --- a/gcc/c-family/c-pragma.cc +++ b/gcc/c-family/c-pragma.cc @@ -781,7 +781,7 @@ public: PK_IGNORED_ATTRIBUTES, PK_DIAGNOSTIC, } pd_kind; - diagnostic_t diagnostic_kind; + enum diagnostics::kind diagnostic_kind; const char *kind_str; const char *option_str; bool own_option_str; @@ -792,7 +792,7 @@ public: valid = false; loc_kind = loc_option = UNKNOWN_LOCATION; pd_kind = PK_INVALID; - diagnostic_kind = DK_UNSPECIFIED; + diagnostic_kind = diagnostics::kind::unspecified; kind_str = option_str = nullptr; own_option_str = false; } @@ -808,7 +808,7 @@ public: kind_str = kind_string; pd_kind = PK_INVALID; - diagnostic_kind = DK_UNSPECIFIED; + diagnostic_kind = diagnostics::kind::unspecified; if (strcmp (kind_str, "push") == 0) pd_kind = PK_PUSH; else if (strcmp (kind_str, "pop") == 0) @@ -818,17 +818,17 @@ public: else if (strcmp (kind_str, "error") == 0) { pd_kind = PK_DIAGNOSTIC; - diagnostic_kind = DK_ERROR; + diagnostic_kind = diagnostics::kind::error; } else if (strcmp (kind_str, "warning") == 0) { pd_kind = PK_DIAGNOSTIC; - diagnostic_kind = DK_WARNING; + diagnostic_kind = diagnostics::kind::warning; } else if (strcmp (kind_str, "ignored") == 0) { pd_kind = PK_DIAGNOSTIC; - diagnostic_kind = DK_IGNORED; + diagnostic_kind = diagnostics::kind::ignored; } } @@ -1016,7 +1016,8 @@ handle_pragma_diagnostic_impl () what we used to do here before and changing it breaks e.g. PR69543 and PR69558. */ control_warning_option (option_index, (int) data.diagnostic_kind, - arg, data.diagnostic_kind != DK_IGNORED, + arg, + data.diagnostic_kind != diagnostics::kind::ignored, input_location, lang_mask, &handlers, &global_options, &global_options_set, global_dc); @@ -1847,7 +1848,9 @@ init_pragma (void) c_register_pragma_with_early_handler ("GCC", "target", handle_pragma_target, handle_pragma_target); - c_register_pragma ("GCC", "optimize", handle_pragma_optimize); + c_register_pragma_with_early_handler ("GCC", "optimize", + handle_pragma_optimize, + handle_pragma_optimize); c_register_pragma_with_early_handler ("GCC", "push_options", handle_pragma_push_options, handle_pragma_push_options); diff --git a/gcc/c-family/c-ubsan.cc b/gcc/c-family/c-ubsan.cc index 78b7868..a64f74e 100644 --- a/gcc/c-family/c-ubsan.cc +++ b/gcc/c-family/c-ubsan.cc @@ -397,8 +397,7 @@ get_bound_from_access_with_size (tree call) return NULL_TREE; tree ref_to_size = CALL_EXPR_ARG (call, 1); - unsigned int class_of_size = TREE_INT_CST_LOW (CALL_EXPR_ARG (call, 2)); - tree type = TREE_TYPE (CALL_EXPR_ARG (call, 3)); + tree type = TREE_TYPE (TREE_TYPE (CALL_EXPR_ARG (call, 2))); tree size = fold_build2 (MEM_REF, type, unshare_expr (ref_to_size), build_int_cst (ptr_type_node, 0)); /* If size is negative value, treat it as zero. */ @@ -410,12 +409,7 @@ get_bound_from_access_with_size (tree call) build_zero_cst (type), size); } - /* Only when class_of_size is 1, i.e, the number of the elements of - the object type, return the size. */ - if (class_of_size != 1) - return NULL_TREE; - else - size = fold_convert (sizetype, size); + size = fold_convert (sizetype, size); return size; } @@ -554,38 +548,317 @@ ubsan_instrument_bounds (location_t loc, tree array, tree *index, *index, bound); } -/* Return true iff T is an array that was instrumented by SANITIZE_BOUNDS. */ + +/* Instrument array bounds for the pointer array address which is + a call to .ACCESS_WITH_SIZE. We create special + builtin, that gets expanded in the sanopt pass, and make an array + dimention of it. POINTER_ADDR is the pointer array's base address. + *INDEX is an index to the array. + IGNORE_OFF_BY_ONE is true if the POINTER_ADDR is not inside an + INDIRECT_REF. + Return NULL_TREE if no instrumentation is emitted. */ + +tree +ubsan_instrument_bounds_pointer_address (location_t loc, tree pointer_addr, + tree *index, + bool ignore_off_by_one) +{ + tree call = pointer_addr; + if (!is_access_with_size_p (call)) + return NULL_TREE; + tree bound = get_bound_from_access_with_size (call); + + if (ignore_off_by_one) + bound = fold_build2 (PLUS_EXPR, TREE_TYPE (bound), bound, + build_int_cst (TREE_TYPE (bound), + 1)); + + /* Don't emit instrumentation in the most common cases. */ + tree idx = NULL_TREE; + if (TREE_CODE (*index) == INTEGER_CST) + idx = *index; + else if (TREE_CODE (*index) == BIT_AND_EXPR + && TREE_CODE (TREE_OPERAND (*index, 1)) == INTEGER_CST) + idx = TREE_OPERAND (*index, 1); + if (idx + && TREE_CODE (bound) == INTEGER_CST + && tree_int_cst_sgn (idx) >= 0 + && tree_int_cst_lt (idx, bound)) + return NULL_TREE; + + *index = save_expr (*index); + + /* Create an array_type for the corresponding pointer array. */ + tree itype = build_range_type (sizetype, size_zero_node, NULL_TREE); + /* The array's element type can be get from the return type of the call to + .ACCESS_WITH_SIZE. */ + tree element_type = TREE_TYPE (TREE_TYPE (call)); + tree array_type = build_array_type (element_type, itype); + /* Create a "(T *) 0" tree node to describe the array type. */ + tree zero_with_type = build_int_cst (build_pointer_type (array_type), 0); + return build_call_expr_internal_loc (loc, IFN_UBSAN_BOUNDS, + void_type_node, 3, zero_with_type, + *index, bound); +} + +/* This structure is to combine a factor with its parent and its position + * in its parent tree. */ +struct factor_t +{ + tree factor; + tree parent; /* the parent tree of this factor. */ + int pos; /* the position of this factor in its parent tree. */ +}; + +/* for a multiply expression like: + ((long unsigned int) m * (long unsigned int) SAVE_EXPR <n>) * 4 + + locate all the factors, the parents of the factor and the position of + the factor in its parent, and put them to VEC_FACTORS. */ + +static void +get_factors_from_mul_expr (tree mult_expr, tree parent, + int pos, auto_vec<factor_t> *vec_factors) +{ + struct factor_t mult_factor = {0, 0, -1}; + mult_factor.factor = mult_expr; + mult_factor.parent = parent; + mult_factor.pos = pos; + + while (CONVERT_EXPR_CODE_P (TREE_CODE (mult_expr))) + { + mult_factor.parent = mult_expr; + mult_factor.pos = 0; + mult_expr = TREE_OPERAND (mult_expr, 0); + mult_factor.factor = mult_expr; + } + if (TREE_CODE (mult_expr) != MULT_EXPR) + vec_factors->safe_push (mult_factor); + else + { + get_factors_from_mul_expr (TREE_OPERAND (mult_expr, 0), mult_expr, + 0, vec_factors); + get_factors_from_mul_expr (TREE_OPERAND (mult_expr, 1), mult_expr, + 1, vec_factors); + } +} + +/* Given an OFFSET expression, and the ELEMENT_SIZE, + get the index expression from OFFSET and return it. + For example: + OFFSET: + ((long unsigned int) m * (long unsigned int) SAVE_EXPR <n>) * 4 + ELEMENT_SIZE: + (sizetype) SAVE_EXPR <n> * 4 + get the index as (long unsigned int) m, and return it. + The INDEX_P holds the pointer to the parent tree of the index, + INDEX_N holds the position of the index in its parent. */ + +static tree +get_index_from_offset (tree offset, tree *index_p, + int *index_n, tree element_size) +{ + if (TREE_CODE (offset) != MULT_EXPR) + return NULL_TREE; + + auto_vec<factor_t> e_factors, o_factors; + get_factors_from_mul_expr (element_size, NULL, -1, &e_factors); + get_factors_from_mul_expr (offset, *index_p, *index_n, &o_factors); + + if (e_factors.is_empty () || o_factors.is_empty ()) + return NULL_TREE; + + bool all_found = true; + for (unsigned i = 0; i < e_factors.length (); i++) + { + factor_t e_size_factor = e_factors[i]; + bool found = false; + for (unsigned j = 0; j < o_factors.length ();) + { + factor_t o_exp_factor = o_factors[j]; + if (operand_equal_p (e_size_factor.factor, o_exp_factor.factor)) + { + o_factors.unordered_remove (j); + found = true; + break; + } + else + j++; + } + if (!found) + all_found = false; + } + + if (!all_found) + return NULL_TREE; + + if (o_factors.length () != 1) + return NULL_TREE; + + *index_p = o_factors[0].parent; + *index_n = o_factors[0].pos; + return o_factors[0].factor; +} + +/* For an pointer + offset computation expression, such as, + .ACCESS_WITH_SIZE (p->c, &p->b, 1, 0, -1, 0B) + + (sizetype) ((long unsigned int) index * 4 + Return the index of this pointer array reference, + set the parent tree of INDEX to *INDEX_P. + set the operand position of the INDEX in the parent tree to *INDEX_N. + If failed, return NULL_TREE. */ + +static tree +get_index_from_pointer_addr_expr (tree pointer, tree *index_p, int *index_n) +{ + *index_p = NULL_TREE; + *index_n = -1; + tree call = TREE_OPERAND (pointer, 0); + if (!is_access_with_size_p (call)) + return NULL_TREE; + + /* Get the pointee type of the call to .ACCESS_WITH_SIZE. + This should be the element type of the pointer array. */ + tree pointee_type = TREE_TYPE (TREE_TYPE (call)); + tree pointee_size = TYPE_SIZE_UNIT (pointee_type); + + tree index_exp = TREE_OPERAND (pointer, 1); + *index_p = pointer; + *index_n = 1; + + if (!(TREE_CODE (index_exp) != MULT_EXPR + && tree_int_cst_equal (pointee_size, integer_one_node))) + { + while (CONVERT_EXPR_CODE_P (TREE_CODE (index_exp))) + { + *index_p = index_exp; + *index_n = 0; + index_exp = TREE_OPERAND (index_exp, 0); + } + index_exp = get_index_from_offset (index_exp, index_p, + index_n, pointee_size); + + if (!index_exp) + return NULL_TREE; + } + + while (CONVERT_EXPR_CODE_P (TREE_CODE (index_exp))) + { + *index_p = index_exp; + *index_n = 0; + index_exp = TREE_OPERAND (index_exp, 0); + } + + return index_exp; +} + +/* Return TRUE when the EXPR is a pointer array address that could be + instrumented. + We only instrument an address computation similar as the following: + .ACCESS_WITH_SIZE (p->c, &p->b, 1, 0, -1, 0B) + + (sizetype) ((long unsigned int) index * 4) + if the EXPR is instrumentable, return TRUE and + set the index to *INDEX. + set the .ACCESS_WITH_SIZE to *BASE. + set the parent tree of INDEX to *INDEX_P. + set the operand position of the INDEX in the parent tree to INDEX_N. */ + +static bool +is_instrumentable_pointer_array_address (tree expr, tree *base, + tree *index, tree *index_p, + int *index_n) +{ + /* For a pointer array address as: + .ACCESS_WITH_SIZE (p->c, &p->b, 1, 0, -1, 0B) + + (sizetype) ((long unsigned int) index * 4) + op0 is the call to .ACCESS_WITH_SIZE; + op1 is the index. */ + if (TREE_CODE (expr) != POINTER_PLUS_EXPR) + return false; + + tree op0 = TREE_OPERAND (expr, 0); + if (!is_access_with_size_p (op0)) + return false; + tree op1 = get_index_from_pointer_addr_expr (expr, index_p, index_n); + if (op1 != NULL_TREE) + { + *base = op0; + *index = op1; + return true; + } + return false; +} + +/* Return true iff T is an array or an indirect reference that was + instrumented by SANITIZE_BOUNDS. */ bool -ubsan_array_ref_instrumented_p (const_tree t) +ubsan_array_ref_instrumented_p (tree t) { - if (TREE_CODE (t) != ARRAY_REF) + if (TREE_CODE (t) != ARRAY_REF + && TREE_CODE (t) != MEM_REF) return false; - tree op1 = TREE_OPERAND (t, 1); - return TREE_CODE (op1) == COMPOUND_EXPR - && TREE_CODE (TREE_OPERAND (op1, 0)) == CALL_EXPR - && CALL_EXPR_FN (TREE_OPERAND (op1, 0)) == NULL_TREE - && CALL_EXPR_IFN (TREE_OPERAND (op1, 0)) == IFN_UBSAN_BOUNDS; + bool is_array = (TREE_CODE (t) == ARRAY_REF); + tree op0 = NULL_TREE; + tree op1 = NULL_TREE; + tree index_p = NULL_TREE; + int index_n = 0; + if (is_array) + { + op1 = TREE_OPERAND (t, 1); + return TREE_CODE (op1) == COMPOUND_EXPR + && TREE_CODE (TREE_OPERAND (op1, 0)) == CALL_EXPR + && CALL_EXPR_FN (TREE_OPERAND (op1, 0)) == NULL_TREE + && CALL_EXPR_IFN (TREE_OPERAND (op1, 0)) == IFN_UBSAN_BOUNDS; + } + else if (is_instrumentable_pointer_array_address (t, &op0, &op1, + &index_p, &index_n)) + return TREE_CODE (op1) == COMPOUND_EXPR + && TREE_CODE (TREE_OPERAND (op1, 0)) == CALL_EXPR + && CALL_EXPR_FN (TREE_OPERAND (op1, 0)) == NULL_TREE + && CALL_EXPR_IFN (TREE_OPERAND (op1, 0)) == IFN_UBSAN_BOUNDS; + + return false; } -/* Instrument an ARRAY_REF, if it hasn't already been instrumented. - IGNORE_OFF_BY_ONE is true if the ARRAY_REF is inside a ADDR_EXPR. */ +/* Instrument an ARRAY_REF or an address computation whose base address is + a call to .ACCESS_WITH_SIZE, if it hasn't already been instrumented. + IGNORE_OFF_BY_ONE is true if the ARRAY_REF is inside a ADDR_EXPR, or the + address computation is not inside a INDIRECT_REF. */ void ubsan_maybe_instrument_array_ref (tree *expr_p, bool ignore_off_by_one) { + tree e = NULL_TREE; + tree op0 = NULL_TREE; + tree op1 = NULL_TREE; + tree index_p = NULL_TREE; /* the parent tree of INDEX. */ + int index_n = 0; /* the operand position of INDEX in the parent tree. */ + if (!ubsan_array_ref_instrumented_p (*expr_p) && sanitize_flags_p (SANITIZE_BOUNDS | SANITIZE_BOUNDS_STRICT) && current_function_decl != NULL_TREE) { - tree op0 = TREE_OPERAND (*expr_p, 0); - tree op1 = TREE_OPERAND (*expr_p, 1); - tree e = ubsan_instrument_bounds (EXPR_LOCATION (*expr_p), op0, &op1, - ignore_off_by_one); + if (TREE_CODE (*expr_p) == ARRAY_REF) + { + op0 = TREE_OPERAND (*expr_p, 0); + op1 = TREE_OPERAND (*expr_p, 1); + index_p = *expr_p; + index_n = 1; + e = ubsan_instrument_bounds (EXPR_LOCATION (*expr_p), op0, + &op1, ignore_off_by_one); + } + else if (is_instrumentable_pointer_array_address (*expr_p, &op0, &op1, + &index_p, &index_n)) + e = ubsan_instrument_bounds_pointer_address (EXPR_LOCATION (*expr_p), + op0, &op1, + ignore_off_by_one); + + /* Replace the original INDEX with the instrumented INDEX. */ if (e != NULL_TREE) - TREE_OPERAND (*expr_p, 1) = build2 (COMPOUND_EXPR, TREE_TYPE (op1), - e, op1); + TREE_OPERAND (index_p, index_n) + = build2 (COMPOUND_EXPR, TREE_TYPE (op1), e, op1); } } diff --git a/gcc/c-family/c-warn.cc b/gcc/c-family/c-warn.cc index d547b08..09517d2 100644 --- a/gcc/c-family/c-warn.cc +++ b/gcc/c-family/c-warn.cc @@ -3835,7 +3835,7 @@ do_warn_array_compare (location_t location, tree_code code, tree op0, tree op1) op1 = TREE_OPERAND (op1, 0); auto_diagnostic_group d; - diagnostic_t kind = DK_WARNING; + enum diagnostics::kind kind = diagnostics::kind::warning; const char *msg; if (c_dialect_cxx () && cxx_dialect >= cxx20) { @@ -3843,7 +3843,7 @@ do_warn_array_compare (location_t location, tree_code code, tree op0, tree op1) if (cxx_dialect >= cxx26) { msg = G_("comparison between two arrays is not allowed in C++26"); - kind = DK_PERMERROR; + kind = diagnostics::kind::permerror; } else msg = G_("comparison between two arrays is deprecated in C++20"); diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 75b6531..3f5e2f0 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -397,6 +397,10 @@ Wassign-intercept ObjC ObjC++ Var(warn_assign_intercept) Warning Warn whenever an Objective-C assignment is being intercepted by the garbage collector. +Wabbreviated-auto-in-template-arg +C++ ObjC++ Warning Var(warn_abbev_auto_targ) Init(1) +Diagnose a placeholder type in a template argument in a function parameter type. + Wbad-function-cast C ObjC Var(warn_bad_function_cast) Warning Warn about casting functions to incompatible types. @@ -493,6 +497,10 @@ Wc++20-compat C++ ObjC++ Var(warn_cxx20_compat) Warning LangEnabledBy(C++ ObjC++,Wall) Init(0) CPP(cpp_warn_cxx20_compat) CppReason(CPP_W_CXX20_COMPAT) Warn about C++ constructs whose meaning differs between ISO C++ 2017 and ISO C++ 2020. +Wc++26-compat +C++ ObjC++ Var(warn_cxx26_compat) Warning LangEnabledBy(C++ ObjC++,Wall) Init(0) +Warn about C++ constructs whose meaning differs between ISO C++ 2023 and ISO C++ 2026. + Wc++11-extensions C++ ObjC++ Var(warn_cxx11_extensions) Warning Init(1) Warn about C++11 constructs in code compiled with an older standard. @@ -938,7 +946,7 @@ C ObjC C++ ObjC++ CPP(cpp_warn_invalid_utf8) CppReason(CPP_W_INVALID_UTF8) Var(w Warn about invalid UTF-8 characters. Wjump-misses-init -C ObjC Var(warn_jump_misses_init) Warning LangEnabledby(C ObjC,Wc++-compat) +C ObjC Var(warn_jump_misses_init) Warning LangEnabledBy(C ObjC,Wc++-compat) Warn when a jump misses a variable initialization. Enum @@ -956,6 +964,10 @@ Enum(warn_leading_whitespace_kind) String(tabs) Value(2) EnumValue Enum(warn_leading_whitespace_kind) String(blanks) Value(3) +Wkeyword-macro +C ObjC C++ ObjC++ CPP(cpp_warn_keyword_macro) CppReason(CPP_W_KEYWORD_MACRO) Var(warn_keyword_macro) Init(0) Warning +Warn about defining or undefining macros with identifiers equal to keywords (or for C++ conditional keywords or standard attribute names). + Wleading-whitespace= C ObjC C++ ObjC++ CPP(cpp_warn_leading_whitespace) CppReason(CPP_W_LEADING_WHITESPACE) Enum(warn_leading_whitespace_kind) Joined RejectNegative Var(warn_leading_whitespace) Init(0) Warning Warn about leading whitespace style issues on lines except when in raw string literals. @@ -1098,6 +1110,10 @@ Wnoexcept-type C++ ObjC++ Warning Var(warn_noexcept_type) LangEnabledBy(C++ ObjC++,Wabi || Wc++17-compat) Warn if C++17 noexcept function type will change the mangled name of a symbol. +Wnon-c-typedef-for-linkage +C++ ObjC++ Var(warn_non_c_typedef_for_linkage) Init(1) Warning +Warn for non-C compatible unnamed classes with a typedef name for linkage purposes. + Wnon-template-friend C++ ObjC++ Var(warn_nontemplate_friend) Init(1) Warning Warn when non-templatized friend functions are declared within a template. @@ -1319,6 +1335,14 @@ Wsequence-point C ObjC C++ ObjC++ Var(warn_sequence_point) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall) Warn about possible violations of sequence point rules. +Wsfinae-incomplete= +C++ ObjC++ Var(warn_sfinae_incomplete) Warning Init(1) Joined RejectNegative UInteger IntegerRange(0, 2) +Warn about an incomplete type affecting semantics in a non-error context. + +Wsfinae-incomplete +C++ ObjC++ Warning Alias(Wsfinae-incomplete=, 1, 0) +Warn about an incomplete type affecting semantics in a non-error context. + Wshadow-ivar ObjC ObjC++ Var(warn_shadow_ivar) EnabledBy(Wshadow) Init(1) Warning Warn if a local declaration hides an instance variable. diff --git a/gcc/c-family/c.opt.urls b/gcc/c-family/c.opt.urls index ad6d8a0..e09d51d 100644 --- a/gcc/c-family/c.opt.urls +++ b/gcc/c-family/c.opt.urls @@ -139,6 +139,9 @@ UrlSuffix(gcc/Warning-Options.html#index-Warray-parameter) Wassign-intercept UrlSuffix(gcc/Objective-C-and-Objective-C_002b_002b-Dialect-Options.html#index-Wassign-intercept) +Wabbreviated-auto-in-template-arg +UrlSuffix(gcc/C_002b_002b-Dialect-Options.html#index-Wabbreviated-auto-in-template-arg) + Wbad-function-cast UrlSuffix(gcc/Warning-Options.html#index-Wbad-function-cast) @@ -187,6 +190,9 @@ UrlSuffix(gcc/Warning-Options.html#index-Wc_002b_002b17-compat) Wc++20-compat UrlSuffix(gcc/Warning-Options.html#index-Wc_002b_002b20-compat) +Wc++26-compat +UrlSuffix(gcc/Warning-Options.html#index-Wc_002b_002b26-compat) + Wc++11-extensions UrlSuffix(gcc/Warning-Options.html#index-Wc_002b_002b11-extensions) @@ -502,6 +508,9 @@ UrlSuffix(gcc/Warning-Options.html#index-Winvalid-utf8) Wjump-misses-init UrlSuffix(gcc/Warning-Options.html#index-Wjump-misses-init) +Wkeyword-macro +UrlSuffix(gcc/Warning-Options.html#index-Wkeyword-macro) + Wleading-whitespace= UrlSuffix(gcc/Warning-Options.html#index-Wleading-whitespace_003d) @@ -604,6 +613,9 @@ UrlSuffix(gcc/C_002b_002b-Dialect-Options.html#index-Wno-noexcept) Wnoexcept-type UrlSuffix(gcc/C_002b_002b-Dialect-Options.html#index-Wno-noexcept-type) +Wnon-c-typedef-for-linkage +UrlSuffix(gcc/C_002b_002b-Dialect-Options.html#index-Wno-non-c-typedef-for-linkage) + Wnon-template-friend UrlSuffix(gcc/C_002b_002b-Dialect-Options.html#index-Wno-non-template-friend) @@ -756,6 +768,12 @@ UrlSuffix(gcc/Warning-Options.html#index-Wno-self-move) Wsequence-point UrlSuffix(gcc/Warning-Options.html#index-Wno-sequence-point) +Wsfinae-incomplete= +UrlSuffix(gcc/C_002b_002b-Dialect-Options.html#index-Wno-sfinae-incomplete) + +Wsfinae-incomplete +UrlSuffix(gcc/C_002b_002b-Dialect-Options.html#index-Wno-sfinae-incomplete) + Wshadow-ivar UrlSuffix(gcc/Warning-Options.html#index-Wno-shadow-ivar) diff --git a/gcc/c-family/known-headers.cc b/gcc/c-family/known-headers.cc index 7e0fa95..e3c0113 100644 --- a/gcc/c-family/known-headers.cc +++ b/gcc/c-family/known-headers.cc @@ -329,9 +329,10 @@ suggest_missing_header::~suggest_missing_header () /* suggest_missing_option's ctor. */ -suggest_missing_option::suggest_missing_option (location_t loc, - const char *macro_name, - diagnostic_option_id option_id) +suggest_missing_option:: +suggest_missing_option (location_t loc, + const char *macro_name, + diagnostics::option_id option_id) : deferred_diagnostic (loc), m_name_str (macro_name), m_option_id (option_id) { gcc_assert (macro_name); diff --git a/gcc/c-family/known-headers.h b/gcc/c-family/known-headers.h index b1da757..3ffe5f3 100644 --- a/gcc/c-family/known-headers.h +++ b/gcc/c-family/known-headers.h @@ -48,12 +48,12 @@ class suggest_missing_option : public deferred_diagnostic { public: suggest_missing_option (location_t loc, const char *name, - diagnostic_option_id option_id); + diagnostics::option_id option_id); ~suggest_missing_option (); private: const char *m_name_str; - diagnostic_option_id m_option_id; + diagnostics::option_id m_option_id; }; #endif /* GCC_KNOWN_HEADERS_H */ |