Message ID | ZqvWUUv6P0K561JG@tucnak |
---|---|
State | New |
Headers | show |
Series | c++: Fix up handling of dependent (late) attributes on function/method types [PR116175] | expand |
On 8/1/24 2:39 PM, Jakub Jelinek wrote: > Hi! > > 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. > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? OK. > 2024-08-01 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.jj 2024-07-31 14:38:54.405628645 +0200 > +++ gcc/cp/pt.cc 2024-08-01 16:29:59.671779469 +0200 > @@ -12219,6 +12219,8 @@ apply_late_template_attributes (tree *de > 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); > @@ -12237,7 +12239,10 @@ apply_late_template_attributes (tree *de > 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; > @@ -14375,8 +14380,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)); > > @@ -14409,7 +14415,9 @@ rebuild_function_or_method_type (tree t, > 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); > @@ -14422,7 +14430,7 @@ rebuild_function_or_method_type (tree t, > 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)) > @@ -14474,7 +14482,7 @@ maybe_rebuild_function_decl_type (tree d > *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); > } > @@ -14657,7 +14665,7 @@ tsubst_function_decl (tree t, tree args, > 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); > @@ -15925,7 +15933,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); > } > > --- gcc/testsuite/g++.dg/ext/attr-format4.C.jj 2024-08-01 17:44:35.492269816 +0200 > +++ gcc/testsuite/g++.dg/ext/attr-format4.C 2024-08-01 17:43:27.340127120 +0200 > @@ -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'" } > > Jakub >
--- gcc/cp/pt.cc.jj 2024-07-31 14:38:54.405628645 +0200 +++ gcc/cp/pt.cc 2024-08-01 16:29:59.671779469 +0200 @@ -12219,6 +12219,8 @@ apply_late_template_attributes (tree *de 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); @@ -12237,7 +12239,10 @@ apply_late_template_attributes (tree *de 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; @@ -14375,8 +14380,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)); @@ -14409,7 +14415,9 @@ rebuild_function_or_method_type (tree t, 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); @@ -14422,7 +14430,7 @@ rebuild_function_or_method_type (tree t, 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)) @@ -14474,7 +14482,7 @@ maybe_rebuild_function_decl_type (tree d *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); } @@ -14657,7 +14665,7 @@ tsubst_function_decl (tree t, tree args, 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); @@ -15925,7 +15933,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); } --- gcc/testsuite/g++.dg/ext/attr-format4.C.jj 2024-08-01 17:44:35.492269816 +0200 +++ gcc/testsuite/g++.dg/ext/attr-format4.C 2024-08-01 17:43:27.340127120 +0200 @@ -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'" }