diff options
Diffstat (limited to 'gcc/c-family')
-rw-r--r-- | gcc/c-family/ChangeLog | 95 | ||||
-rw-r--r-- | gcc/c-family/c-attribs.cc | 212 | ||||
-rw-r--r-- | gcc/c-family/c-common.h | 4 | ||||
-rw-r--r-- | gcc/c-family/c-cppbuiltin.cc | 77 | ||||
-rw-r--r-- | gcc/c-family/c-gimplify.cc | 27 | ||||
-rw-r--r-- | gcc/c-family/c-indentation.cc | 2 | ||||
-rw-r--r-- | gcc/c-family/c-opts.cc | 11 | ||||
-rw-r--r-- | gcc/c-family/c-ubsan.cc | 311 | ||||
-rw-r--r-- | gcc/c-family/c.opt | 8 | ||||
-rw-r--r-- | gcc/c-family/c.opt.urls | 6 |
10 files changed, 685 insertions, 68 deletions
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index a754525..582a282 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,98 @@ +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 diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc index 1f4a0df..1e3a94e 100644 --- a/gcc/c-family/c-attribs.cc +++ b/gcc/c-family/c-attribs.cc @@ -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; } @@ -5736,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 @@ -5812,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. */ { @@ -5831,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 += ','; diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 7c7e21d..b6021d2 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -747,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 @@ -1713,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, diff --git a/gcc/c-family/c-cppbuiltin.cc b/gcc/c-family/c-cppbuiltin.cc index 4aea902..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 @@ -1090,52 +1109,76 @@ c_cpp_builtins (cpp_reader *pfile) 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"); } @@ -1284,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" : ""); @@ -1305,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 ()) 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 bb214fc..d378464 100644 --- a/gcc/c-family/c-indentation.cc +++ b/gcc/c-family/c-indentation.cc @@ -330,7 +330,7 @@ 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) diff --git a/gcc/c-family/c-opts.cc b/gcc/c-family/c-opts.cc index c652e82..0ec30e8 100644 --- a/gcc/c-family/c-opts.cc +++ b/gcc/c-family/c-opts.cc @@ -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. */ @@ -1191,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) { diff --git a/gcc/c-family/c-ubsan.cc b/gcc/c-family/c-ubsan.cc index a4dc310..a64f74e 100644 --- a/gcc/c-family/c-ubsan.cc +++ b/gcc/c-family/c-ubsan.cc @@ -548,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.opt b/gcc/c-family/c.opt index 12877eb..3f5e2f0 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -964,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. @@ -1106,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. diff --git a/gcc/c-family/c.opt.urls b/gcc/c-family/c.opt.urls index 5c97593..e09d51d 100644 --- a/gcc/c-family/c.opt.urls +++ b/gcc/c-family/c.opt.urls @@ -508,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) @@ -610,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) |