diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 2db59213c549f2b30735de3646fc6d5db2b5028e..542962b6387f473c1b42ac9f58edc1cda194e6d5 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 0000000000000000000000000000000000000000..29d39ba72dba4e6bc8324ff176c8d9dd5a177542 --- /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'" }