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