aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2024-08-07 09:48:07 +0200
committerJakub Jelinek <jakub@gcc.gnu.org>2024-08-07 09:48:07 +0200
commit9426ce98ccb35a43b4f3e8ea14dcbf2f5de5dc48 (patch)
treed9d1e5a24a7277c697c33b88bb613fa43baf7933 /gcc
parent2cf89ae83225f932b226cd57ef2d083a59bcf8a3 (diff)
downloadgcc-9426ce98ccb35a43b4f3e8ea14dcbf2f5de5dc48.zip
gcc-9426ce98ccb35a43b4f3e8ea14dcbf2f5de5dc48.tar.gz
gcc-9426ce98ccb35a43b4f3e8ea14dcbf2f5de5dc48.tar.bz2
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.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/pt.cc24
-rw-r--r--gcc/testsuite/g++.dg/ext/attr-format4.C12
2 files changed, 28 insertions, 8 deletions
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 2db5921..542962b 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 0000000..29d39ba
--- /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'" }