c++: printing AGGR_INIT_EXPR args

PR30854 was about wrongly dumping the dummy object argument to a
constructor; r126582 in 4.3 fixed that by skipping the first argument.  But
not all functions called by AGGR_INIT_EXPR are constructors, as observed in
PR116634; we shouldn't skip for non-member functions.  And let's combine the
printing code for CALL_EXPR and AGGR_INIT_EXPR.

This doesn't make us accept the ill-formed 116634 testcase again with a
pedwarn, just fixes the diagnostic issue.

	PR c++/30854
	PR c++/116634

gcc/cp/ChangeLog:

	* error.cc (dump_aggr_init_expr_args): Remove.
	(dump_call_expr_args): Handle AGGR_INIT_EXPR.
	(dump_expr): Combine AGGR_INIT_EXPR and CALL_EXPR cases.

gcc/testsuite/ChangeLog:

	* g++.dg/coroutines/coro-bad-alloc-02-no-op-new-nt.C: Adjust
	diagnostic.
	* g++.dg/diagnostic/aggr-init1.C: New test.
This commit is contained in:
Jason Merrill 2024-10-22 17:45:00 -04:00
parent f003834bad
commit e6d21cbf5c
3 changed files with 55 additions and 62 deletions

View File

@ -84,7 +84,6 @@ static void dump_type_prefix (cxx_pretty_printer *, tree, int);
static void dump_type_suffix (cxx_pretty_printer *, tree, int);
static void dump_function_name (cxx_pretty_printer *, tree, int);
static void dump_call_expr_args (cxx_pretty_printer *, tree, int, bool);
static void dump_aggr_init_expr_args (cxx_pretty_printer *, tree, int, bool);
static void dump_expr_list (cxx_pretty_printer *, tree, int);
static void dump_global_iord (cxx_pretty_printer *, tree);
static void dump_parameters (cxx_pretty_printer *, tree, int);
@ -2253,46 +2252,15 @@ dump_template_parms (cxx_pretty_printer *pp, tree info,
static void
dump_call_expr_args (cxx_pretty_printer *pp, tree t, int flags, bool skipfirst)
{
tree arg;
call_expr_arg_iterator iter;
const int len = call_expr_nargs (t);
pp_cxx_left_paren (pp);
FOR_EACH_CALL_EXPR_ARG (arg, iter, t)
for (int i = skipfirst; i < len; ++i)
{
if (skipfirst)
skipfirst = false;
else
{
dump_expr (pp, arg, flags | TFF_EXPR_IN_PARENS);
if (more_call_expr_args_p (&iter))
pp_separate_with_comma (pp);
}
}
pp_cxx_right_paren (pp);
}
/* Print out the arguments of AGGR_INIT_EXPR T as a parenthesized list
using flags FLAGS. Skip over the first argument if SKIPFIRST is
true. */
static void
dump_aggr_init_expr_args (cxx_pretty_printer *pp, tree t, int flags,
bool skipfirst)
{
tree arg;
aggr_init_expr_arg_iterator iter;
pp_cxx_left_paren (pp);
FOR_EACH_AGGR_INIT_EXPR_ARG (arg, iter, t)
{
if (skipfirst)
skipfirst = false;
else
{
dump_expr (pp, arg, flags | TFF_EXPR_IN_PARENS);
if (more_aggr_init_expr_args_p (&iter))
pp_separate_with_comma (pp);
}
tree arg = get_nth_callarg (t, i);
dump_expr (pp, arg, flags | TFF_EXPR_IN_PARENS);
if (i + 1 < len)
pp_separate_with_comma (pp);
}
pp_cxx_right_paren (pp);
}
@ -2451,28 +2419,9 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
break;
case AGGR_INIT_EXPR:
{
tree fn = NULL_TREE;
if (TREE_CODE (AGGR_INIT_EXPR_FN (t)) == ADDR_EXPR)
fn = TREE_OPERAND (AGGR_INIT_EXPR_FN (t), 0);
if (fn && TREE_CODE (fn) == FUNCTION_DECL)
{
if (DECL_CONSTRUCTOR_P (fn))
dump_type (pp, DECL_CONTEXT (fn), flags);
else
dump_decl (pp, fn, 0);
}
else
dump_expr (pp, AGGR_INIT_EXPR_FN (t), 0);
}
dump_aggr_init_expr_args (pp, t, flags, true);
break;
case CALL_EXPR:
{
tree fn = CALL_EXPR_FN (t);
tree fn = cp_get_callee (t);
bool skipfirst = false;
/* Deal with internal functions. */
@ -2494,8 +2443,10 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
&& NEXT_CODE (fn) == METHOD_TYPE
&& call_expr_nargs (t))
{
tree ob = CALL_EXPR_ARG (t, 0);
if (TREE_CODE (ob) == ADDR_EXPR)
tree ob = get_nth_callarg (t, 0);
if (is_dummy_object (ob))
/* Don't print dummy object. */;
else if (TREE_CODE (ob) == ADDR_EXPR)
{
dump_expr (pp, TREE_OPERAND (ob, 0),
flags | TFF_EXPR_IN_PARENS);
@ -2514,7 +2465,13 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
pp_string (cxx_pp, M_("<ubsan routine call>"));
break;
}
dump_expr (pp, fn, flags | TFF_EXPR_IN_PARENS);
if (TREE_CODE (fn) == FUNCTION_DECL
&& DECL_CONSTRUCTOR_P (fn)
&& is_dummy_object (get_nth_callarg (t, 0)))
dump_type (pp, DECL_CONTEXT (fn), flags);
else
dump_expr (pp, fn, flags | TFF_EXPR_IN_PARENS);
dump_call_expr_args (pp, t, flags, skipfirst);
}
break;

View File

@ -9,7 +9,7 @@
#include "coro1-allocators.h"
struct coro1
f () /* { dg-error {'coro1::promise_type::get_return_object_on_allocation_failure\(\)\(\)' is provided by 'std::__n4861::__coroutine_traits_impl<coro1, void>::promise_type' \{aka 'coro1::promise_type'\} but 'operator new' is not marked 'throw\(\)' or 'noexcept'} } */
f () /* { dg-error {'coro1::promise_type::get_return_object_on_allocation_failure\(\)' is provided by 'std::__n4861::__coroutine_traits_impl<coro1, void>::promise_type' \{aka 'coro1::promise_type'\} but 'operator new' is not marked 'throw\(\)' or 'noexcept'} } */
{
co_return;
}

View File

@ -0,0 +1,36 @@
// PR c++/116634
// { dg-do compile { target c++11 } }
namespace std {
using size_t = decltype(sizeof(42));
}
class ConstString final {
public:
constexpr ConstString() noexcept: buf(), len(0) {}
template<int N>
constexpr ConstString(const char (&a)[N]): buf(a), len(N - 1) {}
constexpr ConstString(const ConstString &c1): buf(c1.buf), len(static_cast<int>(c1.len)) {}
private:
const char* buf;
int len;
};
template<int N>
struct Any final {
constexpr
Any(ConstString (&&_vec)[N]) noexcept: vec(_vec){} // { dg-error "array" }
ConstString vec[N];
};
template<int... N1>
constexpr static
auto Any_of(const char (&...c1)[N1]) -> Any<static_cast<int>(sizeof...(N1))> {
return {{ConstString(c1)...}};
}
int main() {
constexpr static const auto aa1 = Any_of("abcd", "def"); // { dg-message {"abcd", "def"} }
}