On Mon, Apr 11, 2022 at 04:39:22PM -0400, Jason Merrill wrote: > On 4/8/22 15:21, Marek Polacek wrote: > > On Wed, Apr 06, 2022 at 04:55:54PM -0400, Jason Merrill wrote: > > > On 4/1/22 15:14, Marek Polacek wrote: > > > > Attribute format takes three arguments: archetype, string-index, and > > > > first-to-check. The last two specify the position in the function > > > > parameter list. r63030 clarified that "Since non-static C++ methods > > > > have > > > > an implicit this argument, the arguments of such methods should be > > > > counted > > > > from two, not one, when giving values for string-index and > > > > first-to-check." > > > > Therefore one has to write > > > > > > > > struct D { > > > > D(const char *, ...) __attribute__((format(printf, 2, 3))); > > > > }; > > > > > > > > However -- and this is the problem in this PR -- ctors with virtual > > > > bases also get two additional parameters: the in-charge parameter and > > > > the VTT parameter (added in maybe_retrofit_in_chrg). In fact we'll end > > > > up > > > > with two clones of the ctor: an in-charge and a not-in-charge version > > > > (see > > > > build_cdtor_clones). That means that the argument position the user > > > > specified in the attribute argument will refer to different arguments, > > > > depending on which constructor we're currently dealing with. This can > > > > cause a range of problems: wrong errors, confusing warnings, or crashes. > > > > > > > > This patch corrects that; for C we don't have to do anything, and in C++ > > > > we can use num_artificial_parms_for. It would be wrong to rewrite the > > > > attributes the user supplied, so I've added an extra parameter called > > > > adjust_pos. > > > > > > > > Attribute format_arg is not affected, because it requires that the > > > > function returns "const char *" which will never be the case for cdtors. > > > > > > > > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? > > > > > > > > PR c++/101833 > > > > PR c++/47634 > > > > > > > > gcc/c-family/ChangeLog: > > > > > > > > * c-attribs.cc (positional_argument): Add new argument > > > > adjust_pos, > > > > use it. > > > > * c-common.cc (check_function_arguments): Pass fndecl to > > > > check_function_format. > > > > * c-common.h (check_function_format): Adjust declaration. > > > > (maybe_adjust_arg_pos_for_attribute): Add. > > > > (positional_argument): Adjust declaration. > > > > * c-format.cc (decode_format_attr): Add fndecl argument. Pass > > > > it to > > > > maybe_adjust_arg_pos_for_attribute. Adjust calls to > > > > get_constant. > > > > > > I wonder about, instead of adding another parameter, allowing the current > > > fntype parameter to be the fndecl when we have one. > > > > > > And then that gets passed down into positional_argument, so we can call > > > maybe_adjust_arg_pos_for_attribute there, and adjust the return value > > > appropriately so we don't need the extra adjustment in get_constant? > > > > Unfortunately I can't do that. positional_argument can't return the > > adjusted position, because get_constant returns it and in decode_format_attr > > it's used to rewrite the arguments in the attribute list: > > > > tree *format_num_expr = &TREE_VALUE (TREE_CHAIN (args)); > > tree *first_arg_num_expr = &TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args))); > > ... > > if (tree val = get_constant (fntype, atname, *format_num_expr, > > 2, &info->format_num, 0, validated_p, > > adjust_pos)) > > *format_num_expr = val; > > Could we not do that? Currently isn't it just overwriting the value with > the same value after default_conversion?
I think it is. > Maybe do that conversion directly in decode_format_attr instead? I'm afraid I can't move the default_conversion call out of positional_argument because positional_argument is called from a lot of handle_*_attribute functions, and each of those would have to call default_conversion, which we don't want to do. (Failure to call default_conversion would break e.g. g++.dg/cpp0x/constexpr-attribute2.C.) > > Replacing the arguments in the attribute list would lead to problems, > > because > > when we're processing the constructor clone without the additional > > parameters, > > the adjusted argument position would be out of whack at this point. > > > > I've attempted to reduce the number of parameters, but it hardly seemed like > > a win, here's the patch I came up with: > > > > diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc > > index 6e17847ec9e..972476fbdf4 100644 > > --- a/gcc/c-family/c-attribs.cc > > +++ b/gcc/c-family/c-attribs.cc > > @@ -594,7 +594,7 @@ attribute_takes_identifier_p (const_tree attr_id) > > } > > /* Verify that argument value POS at position ARGNO to attribute NAME > > - applied to function TYPE refers to a function parameter at position > > + applied to function FNTYPE refers to a function parameter at position > > POS and the expected type CODE. Treat CODE == INTEGER_TYPE as > > matching all C integral types except bool. If successful, return > > POS after default conversions, if any. Otherwise, issue appropriate > > diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc > > index 6f08b55d4a7..ffa36673ec0 100644 > > --- a/gcc/c-family/c-common.cc > > +++ b/gcc/c-family/c-common.cc > > @@ -6069,7 +6069,7 @@ check_function_arguments (location_t loc, const_tree > > fndecl, const_tree fntype, > > /* Check for errors in format strings. */ > > if (warn_format || warn_suggest_attribute_format) > > - check_function_format (fntype, fndecl, TYPE_ATTRIBUTES (fntype), nargs, > > + check_function_format (fndecl, TYPE_ATTRIBUTES (fntype), nargs, > > argarray, arglocs); > > if (warn_format) > > diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h > > index db6ff07db37..b68dc8f7d69 100644 > > --- a/gcc/c-family/c-common.h > > +++ b/gcc/c-family/c-common.h > > @@ -857,7 +857,7 @@ extern void check_function_arguments_recurse (void (*) > > opt_code); > > extern bool check_builtin_function_arguments (location_t, vec<location_t>, > > tree, tree, int, tree *); > > -extern void check_function_format (const_tree, const_tree, tree, int, tree > > *, > > +extern void check_function_format (const_tree, tree, int, tree *, > > vec<location_t> *); > > extern bool attribute_fallthrough_p (tree); > > extern tree handle_format_attribute (tree *, tree, tree, int, bool *); > > diff --git a/gcc/c-family/c-format.cc b/gcc/c-family/c-format.cc > > index 87ae7bb73b0..6f0199dfcff 100644 > > --- a/gcc/c-family/c-format.cc > > +++ b/gcc/c-family/c-format.cc > > @@ -70,7 +70,7 @@ static GTY(()) tree local_gimple_ptr_node; > > static GTY(()) tree local_cgraph_node_ptr_node; > > static GTY(()) tree locus; > > -static bool decode_format_attr (const_tree, const_tree, tree, tree, > > +static bool decode_format_attr (const_tree, tree, tree, > > function_format_info *, bool); > > static format_type decode_format_type (const char *, bool * = NULL); > > @@ -330,17 +330,19 @@ get_constant (const_tree fntype, const_tree atname, > > tree expr, int argno, > > return NULL_TREE; > > } > > -/* Decode the arguments to a "format" attribute into a > > - function_format_info structure. It is already known that the list > > - is of the right length. If VALIDATED_P is true, then these > > - attributes have already been validated and must not be erroneous; > > - if false, it will give an error message. Returns true if the > > - attributes are successfully decoded, false otherwise. */ > > +/* Decode the arguments to a "format" attribute into a function_format_info > > + structure. It is already known that the list is of the right length. > > If > > + VALIDATED_P is true, then these attributes have already been validated > > and > > + must not be erroneous; if false, it will give an error message. FN is > > + either a FUNCTION_TYPE or a FUNCTION_DECL. Returns true if the > > attributes > > + are successfully decoded, false otherwise. */ > > static bool > > -decode_format_attr (const_tree fntype, const_tree fndecl, tree atname, > > - tree args, function_format_info *info, bool validated_p) > > +decode_format_attr (const_tree fn, tree atname, tree args, > > + function_format_info *info, bool validated_p) > > { > > + const_tree fndecl = TYPE_P (fn) ? NULL_TREE : fn; > > + const_tree fntype = TYPE_P (fn) ? fn : TREE_TYPE (fn); > > tree format_type_id = TREE_VALUE (args); > > /* Note that TREE_VALUE (args) is changed in place below. Ditto > > for the value of the next element on the list. */ > > @@ -1170,7 +1172,7 @@ decode_format_type (const char *s, bool *is_raw /* = > > NULL */) > > attribute themselves. */ > > void > > -check_function_format (const_tree fntype, const_tree fndecl, tree attrs, > > +check_function_format (const_tree fndecl, tree attrs, > > int nargs, tree *argarray, vec<location_t> *arglocs) > > { > > tree a; > > @@ -1184,7 +1186,7 @@ check_function_format (const_tree fntype, const_tree > > fndecl, tree attrs, > > { > > /* Yup; check it. */ > > function_format_info info; > > - decode_format_attr (fntype, fndecl, atname, TREE_VALUE (a), &info, > > + decode_format_attr (fndecl, atname, TREE_VALUE (a), &info, > > /*validated=*/true); > > if (warn_format) > > { > > @@ -5190,7 +5192,7 @@ handle_format_attribute (tree node[3], tree atname, > > tree args, > > if (TREE_CODE (TREE_VALUE (args)) == IDENTIFIER_NODE) > > TREE_VALUE (args) = canonicalize_attr_name (TREE_VALUE (args)); > > - if (!decode_format_attr (type, fndecl, atname, args, &info, > > + if (!decode_format_attr (fndecl ? fndecl : type, atname, args, &info, > > /* validated_p = */false)) > > { > > *no_add_attrs = true; > > Marek