https://gcc.gnu.org/g:1062eec2d431edbd9254683ba9fd30909589c821
commit r16-5176-g1062eec2d431edbd9254683ba9fd30909589c821 Author: Alejandro Colomar <[email protected]> Date: Sun Nov 2 19:45:40 2025 +0100 gcc/: Factor out helper function No functional change intended. gcc/c-family/ChangeLog: * c-warn.cc (warn_parms_array_mismatch): Split out body of per-pair in parameter lists iteration into... (warn_parm_array_mismatch): ...this new function. Signed-off-by: Alejandro Colomar <[email protected]> Diff: --- gcc/c-family/c-warn.cc | 588 +++++++++++++++++++++++++------------------------ 1 file changed, 301 insertions(+), 287 deletions(-) diff --git a/gcc/c-family/c-warn.cc b/gcc/c-family/c-warn.cc index d50129f0396e..5eb735e07070 100644 --- a/gcc/c-family/c-warn.cc +++ b/gcc/c-family/c-warn.cc @@ -3425,349 +3425,363 @@ expr_to_str (pretty_printer &pp, tree expr, const char *dflt) return pp_formatted_text (&pp); } -/* Detect and diagnose a mismatch between an attribute access specification - on the original declaration of FNDECL and that on the parameters NEWPARMS - from its redeclaration. ORIGLOC is the location of the first declaration - (FNDECL's is set to the location of the redeclaration). */ +/* Helper for warn_parms_array_mismatch. Compare the mappings of + two function parameters and diagnose mismatches. ORIGLOC is the + location of the first function declaration. CURP and NEWP are the + parameters in the first and second function declarators, + respectively. PARMPOS is the position of the parameters within the + list of parameter declarations. BUILTIN is true if the function is + a builtin. */ -void -warn_parms_array_mismatch (location_t origloc, tree fndecl, tree newparms) +static void +warn_parm_array_mismatch (location_t origloc, rdwr_map *cur_idx, + rdwr_map *new_idx, tree curp, tree newp, + unsigned parmpos, bool builtin) { - /* The original parameter list (copied from the original declaration - into the current [re]declaration, FNDECL)). The two are equal if - and only if FNDECL is the first declaration. */ - tree curparms = DECL_ARGUMENTS (fndecl); - if (!curparms || !newparms || curparms == newparms) - return; + /* Create an empty access specification and use it for pointers with + no spec of their own. */ + attr_access ptr_spec = { }; - if (TREE_CODE (curparms) != PARM_DECL - || TREE_CODE (newparms) != PARM_DECL) + /* Only check pointers and C++ references. */ + tree curptype = TREE_TYPE (curp); + tree newptype = TREE_TYPE (newp); + if (!POINTER_TYPE_P (curptype) || !POINTER_TYPE_P (newptype)) return; - /* Extract the (possibly empty) attribute access specification from - the declaration and its type (it doesn't yet reflect those created - in response to NEWPARMS). */ - rdwr_map cur_idx; - tree fntype = TREE_TYPE (fndecl); - init_attr_rdwr_indices (&cur_idx, TYPE_ATTRIBUTES (fntype)); - /* Build a (possibly null) chain of access attributes corresponding - to NEWPARMS. */ - const bool builtin = fndecl_built_in_p (fndecl); - tree newattrs = build_attr_access_from_parms (newparms, builtin); + /* Skip mismatches in __builtin_va_list that is commonly + an array but that in declarations of built-ins decays + to a pointer. */ + if (builtin && TREE_TYPE (newptype) == TREE_TYPE (va_list_type_node)) + return; - /* Extract the (possibly empty) attribute access specification from - NEWATTRS. */ - rdwr_map new_idx; - init_attr_rdwr_indices (&new_idx, newattrs); + /* Access specs for the argument on the current (previous) and + new (to replace the current) declarations. Either may be null, + indicating the parameter is an ordinary pointer with no size + associated with it. */ + attr_access *cura = cur_idx->get (parmpos); + attr_access *newa = new_idx->get (parmpos); - if (cur_idx.is_empty () && new_idx.is_empty ()) + if (!newa) { - /* If both specs are empty check pointers to VLAs for mismatches. */ - warn_parm_ptrarray_mismatch (origloc, curparms, newparms); - return; - } - /* ...otherwise, if at least one spec isn't empty there may be mismatches, - such as between f(T*) and f(T[1]), where the former mapping would be - empty. */ + /* Continue if both parameters are pointers with no size + associated with them. */ + if (!cura) + return; - /* Iterate over the two lists of function parameters, comparing their - respective mappings and diagnosing mismatches. */ - unsigned parmpos = 0; - for (tree curp = curparms, newp = newparms; curp; - curp = TREE_CHAIN (curp), newp = TREE_CHAIN (newp), ++parmpos) + /* Otherwise point at PTR_SPEC and set its parameter pointer + and number. */ + newa = &ptr_spec; + newa->ptr = newp; + newa->ptrarg = parmpos; + } + else if (!cura) { - if (!newp) - /* Bail on invalid redeclarations with fewer arguments. */ - return; + cura = &ptr_spec; + cura->ptr = curp; + cura->ptrarg = parmpos; + } - /* Create an empty access specification and use it for pointers with - no spec of their own. */ - attr_access ptr_spec = { }; + /* Set if the parameter is [re]declared as a VLA. */ + const bool cur_vla_p = cura->size || cura->minsize == HOST_WIDE_INT_M1U; + const bool new_vla_p = newa->size || newa->minsize == HOST_WIDE_INT_M1U; - /* Only check pointers and C++ references. */ - tree curptype = TREE_TYPE (curp); - tree newptype = TREE_TYPE (newp); - if (!POINTER_TYPE_P (curptype) || !POINTER_TYPE_P (newptype)) - continue; + if (DECL_P (curp)) + origloc = DECL_SOURCE_LOCATION (curp); + else if (EXPR_P (curp) && EXPR_HAS_LOCATION (curp)) + origloc = EXPR_LOCATION (curp); - /* Skip mismatches in __builtin_va_list that is commonly - an array but that in declarations of built-ins decays - to a pointer. */ - if (builtin && TREE_TYPE (newptype) == TREE_TYPE (va_list_type_node)) - continue; + /* The location of the parameter in the current redeclaration. */ + location_t newloc = DECL_SOURCE_LOCATION (newp); + if (origloc == UNKNOWN_LOCATION) + origloc = newloc; - /* Access specs for the argument on the current (previous) and - new (to replace the current) declarations. Either may be null, - indicating the parameter is an ordinary pointer with no size - associated with it. */ - attr_access *cura = cur_idx.get (parmpos); - attr_access *newa = new_idx.get (parmpos); + const std::string newparmstr = newa->array_as_string (newptype); + const std::string curparmstr = cura->array_as_string (curptype); + if (new_vla_p && !cur_vla_p) + { + if (warning_at (newloc, OPT_Wvla_parameter, + "argument %u of type %s " + "declared as a variable length array", + parmpos + 1, newparmstr.c_str ())) + inform (origloc, + (cura == &ptr_spec + ? G_("previously declared as a pointer %s") + : G_("previously declared as an ordinary array %s")), + curparmstr.c_str ()); + return; + } - if (!newa) + if (newa == &ptr_spec) + { + /* The new declaration uses the pointer form. Detect mismatches + between the pointer and a previous array or VLA forms. */ + if (cura->minsize == HOST_WIDE_INT_M1U) { - /* Continue if both parameters are pointers with no size - associated with them. */ - if (!cura) - continue; - - /* Otherwise point at PTR_SPEC and set its parameter pointer - and number. */ - newa = &ptr_spec; - newa->ptr = newp; - newa->ptrarg = parmpos; + /* Diagnose a pointer/VLA mismatch. */ + if (warning_at (newloc, OPT_Wvla_parameter, + "argument %u of type %s declared as a pointer", + parmpos + 1, newparmstr.c_str ())) + inform (origloc, + "previously declared as a variable length array %s", + curparmstr.c_str ()); + return; } - else if (!cura) + + if (cura->minsize && cura->minsize != HOST_WIDE_INT_M1U) { - cura = &ptr_spec; - cura->ptr = curp; - cura->ptrarg = parmpos; + /* Diagnose mismatches between arrays with a constant + bound and pointers. */ + if (warning_at (newloc, OPT_Warray_parameter_, + "argument %u of type %s declared as a pointer", + parmpos + 1, newparmstr.c_str ())) + inform (origloc, "previously declared as an array %s", + curparmstr.c_str ()); + return; } + } - /* Set if the parameter is [re]declared as a VLA. */ - const bool cur_vla_p = cura->size || cura->minsize == HOST_WIDE_INT_M1U; - const bool new_vla_p = newa->size || newa->minsize == HOST_WIDE_INT_M1U; + if (!new_vla_p && cur_vla_p) + { + if (warning_at (newloc, OPT_Wvla_parameter, + "argument %u of type %s declared as an ordinary array", + parmpos + 1, newparmstr.c_str ())) + inform (origloc, "previously declared as a variable length array %s", + curparmstr.c_str ()); + return; + } - if (DECL_P (curp)) - origloc = DECL_SOURCE_LOCATION (curp); - else if (EXPR_P (curp) && EXPR_HAS_LOCATION (curp)) - origloc = EXPR_LOCATION (curp); + /* Move on to the next pair of parameters if both of the current + pair are VLAs with a single variable bound that refers to + a parameter at the same position. */ + if (newa->size && cura->size + && newa->sizarg != UINT_MAX + && newa->sizarg == cura->sizarg + && newa->minsize == cura->minsize + && !TREE_PURPOSE (newa->size) && !TREE_PURPOSE (cura->size)) + return; - /* The location of the parameter in the current redeclaration. */ - location_t newloc = DECL_SOURCE_LOCATION (newp); - if (origloc == UNKNOWN_LOCATION) - origloc = newloc; + if (newa->size || cura->size) + { + unsigned newunspec, curunspec; + unsigned newbnds = newa->vla_bounds (&newunspec) + newunspec; + unsigned curbnds = cura->vla_bounds (&curunspec) + curunspec; - const std::string newparmstr = newa->array_as_string (newptype); - const std::string curparmstr = cura->array_as_string (curptype); - if (new_vla_p && !cur_vla_p) + if (newbnds != curbnds) { - if (warning_at (newloc, OPT_Wvla_parameter, - "argument %u of type %s declared as " - "a variable length array", - parmpos + 1, newparmstr.c_str ())) - inform (origloc, - (cura == &ptr_spec - ? G_("previously declared as a pointer %s") - : G_("previously declared as an ordinary array %s")), - curparmstr.c_str ()); - continue; + if (warning_n (newloc, OPT_Wvla_parameter, newbnds, + "argument %u of type %s declared with " + "%u variable bound", + "argument %u of type %s declared with " + "%u variable bounds", + parmpos + 1, newparmstr.c_str (), + newbnds)) + inform_n (origloc, curbnds, + "previously declared as %s with %u variable bound", + "previously declared as %s with %u variable bounds", + curparmstr.c_str (), curbnds); + return; } - if (newa == &ptr_spec) + if (newunspec > curunspec) { - /* The new declaration uses the pointer form. Detect mismatches - between the pointer and a previous array or VLA forms. */ - if (cura->minsize == HOST_WIDE_INT_M1U) - { - /* Diagnose a pointer/VLA mismatch. */ - if (warning_at (newloc, OPT_Wvla_parameter, - "argument %u of type %s declared " - "as a pointer", - parmpos + 1, newparmstr.c_str ())) - inform (origloc, - "previously declared as a variable length array %s", - curparmstr.c_str ()); - continue; - } - - if (cura->minsize && cura->minsize != HOST_WIDE_INT_M1U) + location_t warnloc = newloc, noteloc = origloc; + const char *warnparmstr = newparmstr.c_str (); + const char *noteparmstr = curparmstr.c_str (); + unsigned warnunspec = newunspec, noteunspec = curunspec; + + if (warning_n (warnloc, OPT_Wvla_parameter, warnunspec, + "argument %u of type %s declared with " + "%u unspecified variable bound", + "argument %u of type %s declared with " + "%u unspecified variable bounds", + parmpos + 1, warnparmstr, warnunspec)) { - /* Diagnose mismatches between arrays with a constant - bound and pointers. */ - if (warning_at (newloc, OPT_Warray_parameter_, - "argument %u of type %s declared " - "as a pointer", - parmpos + 1, newparmstr.c_str ())) - inform (origloc, "previously declared as an array %s", - curparmstr.c_str ()); - continue; + if (warnloc == newloc) + inform_n (noteloc, noteunspec, + "previously declared as %s with " + "%u unspecified variable bound", + "previously declared as %s with " + "%u unspecified variable bounds", + noteparmstr, noteunspec); + else + inform_n (noteloc, noteunspec, + "subsequently declared as %s with " + "%u unspecified variable bound", + "subsequently declared as %s with " + "%u unspecified variable bounds", + noteparmstr, noteunspec); } + return; } + } - if (!new_vla_p && cur_vla_p) - { - if (warning_at (newloc, OPT_Wvla_parameter, - "argument %u of type %s declared " - "as an ordinary array", - parmpos + 1, newparmstr.c_str ())) - inform (origloc, - "previously declared as a variable length array %s", - curparmstr.c_str ()); - continue; - } + /* Iterate over the lists of VLA variable bounds, comparing each + pair for equality, and diagnosing mismatches. */ + for (tree newvbl = newa->size, curvbl = cura->size; newvbl && curvbl; + newvbl = TREE_CHAIN (newvbl), curvbl = TREE_CHAIN (curvbl)) + { + tree newpos = TREE_PURPOSE (newvbl); + tree curpos = TREE_PURPOSE (curvbl); + + tree newbnd = vla_bound_parm_decl (TREE_VALUE (newvbl)); + tree curbnd = vla_bound_parm_decl (TREE_VALUE (curvbl)); - /* Move on to the next pair of parameters if both of the current - pair are VLAs with a single variable bound that refers to - a parameter at the same position. */ - if (newa->size && cura->size - && newa->sizarg != UINT_MAX - && newa->sizarg == cura->sizarg - && newa->minsize == cura->minsize - && !TREE_PURPOSE (newa->size) && !TREE_PURPOSE (cura->size)) + if (newpos == curpos && newbnd == curbnd) + /* In the expected case when both bounds either refer to + the same positional parameter or when neither does, + and both are the same expression they are necessarily + the same. */ continue; - if (newa->size || cura->size) - { - unsigned newunspec, curunspec; - unsigned newbnds = newa->vla_bounds (&newunspec) + newunspec; - unsigned curbnds = cura->vla_bounds (&curunspec) + curunspec; + pretty_printer pp1, pp2; + const char* const newbndstr = expr_to_str (pp1, newbnd, "*"); + const char* const curbndstr = expr_to_str (pp2, curbnd, "*"); - if (newbnds != curbnds) + if (!newpos != !curpos + || (newpos && !tree_int_cst_equal (newpos, curpos))) + { + /* Diagnose a mismatch between a specified VLA bound and + an unspecified one. This can only happen in the most + significant bound. + + Distinguish between the common case of bounds that are + other function parameters such as in + f (int n, int[n]); + and others. */ + + gcc_rich_location richloc (newloc); + bool warned; + if (newpos) { - if (warning_n (newloc, OPT_Wvla_parameter, newbnds, - "argument %u of type %s declared with " - "%u variable bound", - "argument %u of type %s declared with " - "%u variable bounds", - parmpos + 1, newparmstr.c_str (), - newbnds)) - inform_n (origloc, curbnds, - "previously declared as %s with %u variable bound", - "previously declared as %s with %u variable bounds", - curparmstr.c_str (), curbnds); - continue; + /* Also underline the VLA bound argument. */ + richloc.add_range (DECL_SOURCE_LOCATION (newbnd)); + warned = warning_at (&richloc, OPT_Wvla_parameter, + "argument %u of type %s " + "declared with mismatched bound argument %E", + parmpos + 1, newparmstr.c_str (), + plus_one (newpos)); } + else + warned = warning_at (&richloc, OPT_Wvla_parameter, + "argument %u of type %s " + "declared with mismatched bound %qs", + parmpos + 1, newparmstr.c_str (), + newbndstr); - if (newunspec > curunspec) + if (warned) { - location_t warnloc = newloc, noteloc = origloc; - const char *warnparmstr = newparmstr.c_str (); - const char *noteparmstr = curparmstr.c_str (); - unsigned warnunspec = newunspec, noteunspec = curunspec; - - if (warning_n (warnloc, OPT_Wvla_parameter, warnunspec, - "argument %u of type %s declared with " - "%u unspecified variable bound", - "argument %u of type %s declared with " - "%u unspecified variable bounds", - parmpos + 1, warnparmstr, warnunspec)) + gcc_rich_location richloc (origloc); + if (curpos) { - if (warnloc == newloc) - inform_n (noteloc, noteunspec, - "previously declared as %s with %u unspecified " - "variable bound", - "previously declared as %s with %u unspecified " - "variable bounds", - noteparmstr, noteunspec); - else - inform_n (noteloc, noteunspec, - "subsequently declared as %s with %u unspecified " - "variable bound", - "subsequently declared as %s with %u unspecified " - "variable bounds", - noteparmstr, noteunspec); + /* Also underline the VLA bound argument. */ + richloc.add_range (DECL_SOURCE_LOCATION (curbnd)); + inform (&richloc, + "previously declared as %s with bound argument %E", + curparmstr.c_str (), plus_one (curpos)); } + else + inform (&richloc, + "previously declared as %s with bound %qs", + curparmstr.c_str (), curbndstr); + continue; } } - /* Iterate over the lists of VLA variable bounds, comparing each - pair for equality, and diagnosing mismatches. */ - for (tree newvbl = newa->size, curvbl = cura->size; newvbl && curvbl; - newvbl = TREE_CHAIN (newvbl), curvbl = TREE_CHAIN (curvbl)) + if (!newpos && newbnd && curbnd) { - tree newpos = TREE_PURPOSE (newvbl); - tree curpos = TREE_PURPOSE (curvbl); + /* The VLA bounds don't refer to other function parameters. + Compare them lexicographically to detect gross mismatches + such as between T[foo()] and T[bar()]. */ + if (operand_equal_p (newbnd, curbnd, + OEP_DECL_NAME | OEP_LEXICOGRAPHIC)) + continue; - tree newbnd = vla_bound_parm_decl (TREE_VALUE (newvbl)); - tree curbnd = vla_bound_parm_decl (TREE_VALUE (curvbl)); + if (warning_at (newloc, OPT_Wvla_parameter, + "argument %u of type %s " + "declared with mismatched bound %qs", + parmpos + 1, newparmstr.c_str (), newbndstr)) + inform (origloc, "previously declared as %s with bound %qs", + curparmstr.c_str (), curbndstr); + continue; + } + } - if (newpos == curpos && newbnd == curbnd) - /* In the expected case when both bounds either refer to - the same positional parameter or when neither does, - and both are the same expression they are necessarily - the same. */ - continue; + if (newa->minsize == cura->minsize + || (((newa->minsize == 0 && newa->mode != access_deferred) + || (cura->minsize == 0 && cura->mode != access_deferred)) + && newa != &ptr_spec + && cura != &ptr_spec)) + return; - pretty_printer pp1, pp2; - const char* const newbndstr = expr_to_str (pp1, newbnd, "*"); - const char* const curbndstr = expr_to_str (pp2, curbnd, "*"); + if (!newa->static_p && !cura->static_p && warn_array_parameter < 2) + /* Avoid warning about mismatches in ordinary (non-static) arrays + at levels below 2. */ + return; - if (!newpos != !curpos - || (newpos && !tree_int_cst_equal (newpos, curpos))) - { - /* Diagnose a mismatch between a specified VLA bound and - an unspecified one. This can only happen in the most - significant bound. - - Distinguish between the common case of bounds that are - other function parameters such as in - f (int n, int[n]); - and others. */ - - gcc_rich_location richloc (newloc); - bool warned; - if (newpos) - { - /* Also underline the VLA bound argument. */ - richloc.add_range (DECL_SOURCE_LOCATION (newbnd)); - warned = warning_at (&richloc, OPT_Wvla_parameter, - "argument %u of type %s declared " - "with mismatched bound argument %E", - parmpos + 1, newparmstr.c_str (), - plus_one (newpos)); - } - else - warned = warning_at (&richloc, OPT_Wvla_parameter, - "argument %u of type %s declared " - "with mismatched bound %qs", - parmpos + 1, newparmstr.c_str (), - newbndstr); + if (warning_at (newloc, OPT_Warray_parameter_, + "argument %u of type %s with mismatched bound", + parmpos + 1, newparmstr.c_str ())) + inform (origloc, "previously declared as %s", curparmstr.c_str ()); +} - if (warned) - { - gcc_rich_location richloc (origloc); - if (curpos) - { - /* Also underline the VLA bound argument. */ - richloc.add_range (DECL_SOURCE_LOCATION (curbnd)); - inform (&richloc, "previously declared as %s with " - "bound argument %E", - curparmstr.c_str (), plus_one (curpos)); - } - else - inform (&richloc, "previously declared as %s with bound " - "%qs", curparmstr.c_str (), curbndstr); +/* Detect and diagnose a mismatch between an attribute access specification + on the original declaration of FNDECL and that on the parameters NEWPARMS + from its redeclaration. ORIGLOC is the location of the first declaration + (FNDECL's is set to the location of the redeclaration). */ - continue; - } - } +void +warn_parms_array_mismatch (location_t origloc, tree fndecl, tree newparms) +{ + /* The original parameter list (copied from the original declaration + into the current [re]declaration, FNDECL)). The two are equal if + and only if FNDECL is the first declaration. */ + tree curparms = DECL_ARGUMENTS (fndecl); + if (!curparms || !newparms || curparms == newparms) + return; - if (!newpos && newbnd && curbnd) - { - /* The VLA bounds don't refer to other function parameters. - Compare them lexicographically to detect gross mismatches - such as between T[foo()] and T[bar()]. */ - if (operand_equal_p (newbnd, curbnd, - OEP_DECL_NAME | OEP_LEXICOGRAPHIC)) - continue; - - if (warning_at (newloc, OPT_Wvla_parameter, - "argument %u of type %s declared with " - "mismatched bound %qs", - parmpos + 1, newparmstr.c_str (), newbndstr)) - inform (origloc, "previously declared as %s with bound %qs", - curparmstr.c_str (), curbndstr); - continue; - } - } + if (TREE_CODE (curparms) != PARM_DECL + || TREE_CODE (newparms) != PARM_DECL) + return; + /* Extract the (possibly empty) attribute access specification from + the declaration and its type (it doesn't yet reflect those created + in response to NEWPARMS). */ + rdwr_map cur_idx; + tree fntype = TREE_TYPE (fndecl); + init_attr_rdwr_indices (&cur_idx, TYPE_ATTRIBUTES (fntype)); - if (newa->minsize == cura->minsize - || (((newa->minsize == 0 && newa->mode != access_deferred) - || (cura->minsize == 0 && cura->mode != access_deferred)) - && newa != &ptr_spec - && cura != &ptr_spec)) - continue; + /* Build a (possibly null) chain of access attributes corresponding + to NEWPARMS. */ + const bool builtin = fndecl_built_in_p (fndecl); + tree newattrs = build_attr_access_from_parms (newparms, builtin); - if (!newa->static_p && !cura->static_p && warn_array_parameter < 2) - /* Avoid warning about mismatches in ordinary (non-static) arrays - at levels below 2. */ - continue; + /* Extract the (possibly empty) attribute access specification from + NEWATTRS. */ + rdwr_map new_idx; + init_attr_rdwr_indices (&new_idx, newattrs); - if (warning_at (newloc, OPT_Warray_parameter_, - "argument %u of type %s with mismatched bound", - parmpos + 1, newparmstr.c_str ())) - inform (origloc, "previously declared as %s", curparmstr.c_str ()); + if (cur_idx.is_empty () && new_idx.is_empty ()) + { + /* If both specs are empty check pointers to VLAs for mismatches. */ + warn_parm_ptrarray_mismatch (origloc, curparms, newparms); + return; + } + /* ...otherwise, if at least one spec isn't empty there may be mismatches, + such as between f(T*) and f(T[1]), where the former mapping would be + empty. */ + + /* Iterate over the two lists of function parameters, comparing their + respective mappings and diagnosing mismatches. */ + unsigned parmpos = 0; + for (tree curp = curparms, newp = newparms; curp; + curp = TREE_CHAIN (curp), newp = TREE_CHAIN (newp), ++parmpos) + { + if (!newp) + /* Bail on invalid redeclarations with fewer arguments. */ + return; + + warn_parm_array_mismatch (origloc, &cur_idx, &new_idx, curp, newp, parmpos, + builtin); } }
