From 9426ce98ccb35a43b4f3e8ea14dcbf2f5de5dc48 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek <jakub@redhat.com> Date: Wed, 7 Aug 2024 09:48:07 +0200 Subject: [PATCH] c++: Fix up handling of dependent (late) attributes on function/method types [PR116175] When working on unsequenced/reproducible attributes, I've noticed that on templates for some attributes decl_attributes isn't called at all, so they are kept in TYPE_ATTRIBUTES without any verification/transformations and also without argument substitution. The following patch fixes that for FUNCTION/METHOD_TYPE attributes. The included testcase ICEs without the pt.cc changes. 2024-08-07 Jakub Jelinek <jakub@redhat.com> PR c++/116175 * pt.cc (apply_late_template_attributes): For function/method types call cp_build_type_attribute_variant on the non-dependent attributes. (rebuild_function_or_method_type): Add ARGS argument. Use apply_late_template_attributes rather than cp_build_type_attribute_variant. (maybe_rebuild_function_decl_type): Add ARGS argument, pass it to rebuild_function_or_method_type. (tsubst_function_decl): Adjust caller. (tsubst_function_type): Adjust rebuild_function_or_method_type caller. * g++.dg/ext/attr-format4.C: New test. --- gcc/cp/pt.cc | 24 ++++++++++++++++-------- gcc/testsuite/g++.dg/ext/attr-format4.C | 12 ++++++++++++ 2 files changed, 28 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/g++.dg/ext/attr-format4.C diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 2db59213c549..542962b6387f 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -12201,6 +12201,8 @@ apply_late_template_attributes (tree *decl_p, tree attributes, int attr_flags, to our attributes parameter. */ gcc_assert (*p == attributes); } + else if (FUNC_OR_METHOD_TYPE_P (*decl_p)) + p = NULL; else { p = &TYPE_ATTRIBUTES (*decl_p); @@ -12219,7 +12221,10 @@ apply_late_template_attributes (tree *decl_p, tree attributes, int attr_flags, tree nondep = t; /* Apply any non-dependent attributes. */ - *p = nondep; + if (p) + *p = nondep; + else if (nondep) + *decl_p = cp_build_type_attribute_variant (*decl_p, nondep); if (nondep == attributes) return true; @@ -14377,8 +14382,9 @@ lookup_explicit_specifier (tree v) identical to T. */ static tree -rebuild_function_or_method_type (tree t, tree return_type, tree arg_types, - tree raises, tsubst_flags_t complain) +rebuild_function_or_method_type (tree t, tree args, tree return_type, + tree arg_types, tree raises, + tsubst_flags_t complain) { gcc_assert (FUNC_OR_METHOD_TYPE_P (t)); @@ -14411,7 +14417,9 @@ rebuild_function_or_method_type (tree t, tree return_type, tree arg_types, new_type = build_method_type_directly (r, return_type, TREE_CHAIN (arg_types)); } - new_type = cp_build_type_attribute_variant (new_type, TYPE_ATTRIBUTES (t)); + if (!apply_late_template_attributes (&new_type, TYPE_ATTRIBUTES (t), 0, + args, complain, NULL_TREE)) + return error_mark_node; cp_ref_qualifier rqual = type_memfn_rqual (t); bool late_return_type_p = TYPE_HAS_LATE_RETURN_TYPE (t); @@ -14424,7 +14432,7 @@ rebuild_function_or_method_type (tree t, tree return_type, tree arg_types, resolution for Core issues 1001/1322. */ static void -maybe_rebuild_function_decl_type (tree decl) +maybe_rebuild_function_decl_type (tree decl, tree args) { bool function_type_needs_rebuilding = false; if (tree parm_list = FUNCTION_FIRST_USER_PARM (decl)) @@ -14476,7 +14484,7 @@ maybe_rebuild_function_decl_type (tree decl) *q = void_list_node; TREE_TYPE (decl) - = rebuild_function_or_method_type (fntype, + = rebuild_function_or_method_type (fntype, args, TREE_TYPE (fntype), new_parm_type_list, TYPE_RAISES_EXCEPTIONS (fntype), tf_none); } @@ -14659,7 +14667,7 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain, DECL_ARGUMENTS (r) = parms; DECL_RESULT (r) = NULL_TREE; - maybe_rebuild_function_decl_type (r); + maybe_rebuild_function_decl_type (r, args); TREE_STATIC (r) = 0; TREE_PUBLIC (r) = TREE_PUBLIC (t); @@ -15927,7 +15935,7 @@ tsubst_function_type (tree t, } /* Construct a new type node and return it. */ - return rebuild_function_or_method_type (t, return_type, arg_types, + return rebuild_function_or_method_type (t, args, return_type, arg_types, /*raises=*/NULL_TREE, complain); } diff --git a/gcc/testsuite/g++.dg/ext/attr-format4.C b/gcc/testsuite/g++.dg/ext/attr-format4.C new file mode 100644 index 000000000000..29d39ba72dba --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/attr-format4.C @@ -0,0 +1,12 @@ +// PR c++/116175 +// { dg-do compile { target c++11 } } +// { dg-options "-Wformat" } + +template <typename ...T> +int foo (T ...args, const char *fmt, ...) +[[gnu::format (printf, 1 + sizeof... (T), 2 + sizeof... (T))]]; + +int a = foo <> ("%d", 1); +int b = foo <int, int, int, int, int> (1, 2, 3, 4, 5, "%d", 1); +int c = foo <> ("%f", 1); // { dg-warning "format '%f' expects argument of type 'double', but argument 2 has type 'int'" } +int d = foo <int, int, int, int, int> (1, 2, 3, 4, 5, "%f", 1); // { dg-warning "format '%f' expects argument of type 'double', but argument 7 has type 'int'" } -- GitLab