c, c++: attribute format on a ctor with a vbase [PR101833, PR47634]
commit0c723bb4be2a67657828b692997855afcdc5d286
authorMarek Polacek <polacek@redhat.com>
Thu, 31 Mar 2022 22:31:39 +0000 (31 18:31 -0400)
committerMarek Polacek <polacek@redhat.com>
Sat, 7 May 2022 14:33:25 +0000 (7 10:33 -0400)
tree38c8c63369f73a22cf6476c909890304e55633bb
parentea3fbfda608a148f112f1d2f4bdd0e8bf9429cd9
c, c++: attribute format on a ctor with a vbase [PR101833, PR47634]

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 changed POS to be passed by
reference so that we don't have to change all the call sites of
positional_argument and we still get the default_conversion adjustment.

Attribute format_arg is not affected, because it requires that the
function returns "const char *" which will never be the case for cdtors.

PR c++/101833
PR c++/47634

gcc/c-family/ChangeLog:

* c-attribs.cc (positional_argument): Pass POS by reference.  Deal
with FN being either a function declaration or function type.  Use
maybe_adjust_arg_pos_for_attribute.
* c-common.cc (check_function_arguments): Maybe pass FNDECL down to
check_function_format.
* c-common.h (maybe_adjust_arg_pos_for_attribute): Declare.
(positional_argument): Adjust.
* c-format.cc (get_constant): Rename to ...
(validate_constant): ... this.  Take EXPR by reference.  Return bool
instead of tree.
(handle_format_arg_attribute): Don't overwrite FORMAT_NUM_EXPR by the
return value of validate_constant.
(decode_format_attr): Don't overwrite FORMAT_NUM_EXPR and
FIRST_ARG_NUM_EXPR by the return value of validate_constant.
(check_function_format): Adjust a parameter name.
(handle_format_attribute): Maybe pass FNDECL down to decode_format_attr.

gcc/c/ChangeLog:

* c-objc-common.cc (maybe_adjust_arg_pos_for_attribute): New.

gcc/cp/ChangeLog:

* tree.cc (maybe_adjust_arg_pos_for_attribute): New.

gcc/ChangeLog:

* tree-core.h (struct attribute_spec): Update comment for HANDLER.

gcc/testsuite/ChangeLog:

* g++.dg/ext/attr-format-arg1.C: New test.
* g++.dg/ext/attr-format1.C: New test.
* g++.dg/ext/attr-format2.C: New test.
* g++.dg/ext/attr-format3.C: New test.
gcc/c-family/c-attribs.cc
gcc/c-family/c-common.cc
gcc/c-family/c-common.h
gcc/c-family/c-format.cc
gcc/c/c-objc-common.cc
gcc/cp/tree.cc
gcc/testsuite/g++.dg/ext/attr-format-arg1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/attr-format1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/attr-format2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/attr-format3.C [new file with mode: 0644]
gcc/tree-core.h