[PATCH] c++, contracts: Fix incorrect parameter mapping for postconditions in functions with template parameter packs. [PR124395]
Wang Jinghao <[email protected]>
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <[email protected]> |
Bootstrapped/regtested on x86_64-pc-linux-gnu. -- >8 -- `check_postconditions_in_redecl()' assumes that the parameters in a function redeclaration correspond one to one with those in the previous declaration. This assumption does not hold for parameter packs. As a result, if the original declaration contains a parameter pack and the pack is instantiated with no arguments, a segmentation fault occurs. Likewise, when the parameter pack is instantiated with multiple arguments, type checking is skipped for all instantiated parameters except the first one. PR c++/124395 gcc/cp/ChangeLog: * contracts.cc (maybe_propagate_used_in_post_flag): New function. Contains the logic moved from check_postconditions_in_redecl for checking parameters in redeclarations. (check_postconditions_in_redecl): Fix parameter pack handing gcc/testsuite/ChangeLog: * g++.dg/contracts/cpp26/pr124395.C: New test. Signed-off-by: Wang Jinghao <[email protected]> --- gcc/cp/contracts.cc | 54 +++++++++++++------ .../g++.dg/contracts/cpp26/pr124395.C | 12 +++++ 2 files changed, 51 insertions(+), 15 deletions(-) create mode 100644 gcc/testsuite/g++.dg/contracts/cpp26/pr124395.C diff --git a/gcc/cp/contracts.cc b/gcc/cp/contracts.cc index bc9f23ba4cf..e3b472c178f 100644 --- a/gcc/cp/contracts.cc +++ b/gcc/cp/contracts.cc @@ -538,6 +538,28 @@ parm_used_in_post_p (const_tree decl) return ((TREE_CODE (decl) == PARM_DECL) && DECL_LANG_FLAG_4 (decl)); } +/* Propagate the postcondition use of old parameter to new parameter if OLD_PARM + is ODR used in a postcondition. */ + +static void +maybe_propagate_used_in_post_flag (tree olddecl, tree oldparm, tree newparm) +{ + if (!parm_used_in_post_p (oldparm)) + return; + + set_parm_used_in_post (newparm); + if (!dependent_type_p (TREE_TYPE (newparm)) + && !CP_TYPE_CONST_P (TREE_TYPE (newparm)) + && !TREE_READONLY (newparm)) + { + auto_diagnostic_group d; + error_at (DECL_SOURCE_LOCATION (newparm), + "value parameter %qE used in a postcondition must be const", + newparm); + inform (DECL_SOURCE_LOCATION (olddecl), "previous declaration here"); + } +} + /* If declaration DECL is a PARM_DECL and it appears in a postcondition, then check that it is not a non-const by-value param. LOCATION is where the expression was found and is used for diagnostic purposes. */ @@ -579,27 +601,29 @@ check_postconditions_in_redecl (tree olddecl, tree newdecl) if (!contract_spec) return; - tree t1 = FUNCTION_FIRST_USER_PARM (olddecl); - tree t2 = FUNCTION_FIRST_USER_PARM (newdecl); + tree oldparm = FUNCTION_FIRST_USER_PARM (olddecl); + tree newparm = FUNCTION_FIRST_USER_PARM (newdecl); - for (; t1 && t1 != void_list_node; - t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2)) + for (; oldparm && TREE_CODE (oldparm) == PARM_DECL; + oldparm = DECL_CHAIN (oldparm)) { - if (parm_used_in_post_p (t1)) + if (DECL_PACK_P (oldparm)) { - set_parm_used_in_post (t2); - if (!dependent_type_p (TREE_TYPE (t2)) - && !CP_TYPE_CONST_P (TREE_TYPE (t2)) - && !TREE_READONLY (t2)) + while (newparm && TREE_CODE (newparm) == PARM_DECL + && function_parameter_expanded_from_pack_p (newparm, oldparm)) { - auto_diagnostic_group d; - error_at (DECL_SOURCE_LOCATION (t2), - "value parameter %qE used in a postcondition must be " - "const", t2); - inform (DECL_SOURCE_LOCATION (olddecl), - "previous declaration here"); + maybe_propagate_used_in_post_flag (olddecl, oldparm, newparm); + newparm = DECL_CHAIN (newparm); } } + else + { + if (!newparm || TREE_CODE (newparm) != PARM_DECL) + return; + + maybe_propagate_used_in_post_flag (olddecl, oldparm, newparm); + newparm = DECL_CHAIN (newparm); + } } } diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/pr124395.C b/gcc/testsuite/g++.dg/contracts/cpp26/pr124395.C new file mode 100644 index 00000000000..0ad4e0b9bc9 --- /dev/null +++ b/gcc/testsuite/g++.dg/contracts/cpp26/pr124395.C @@ -0,0 +1,12 @@ +// PR c++/124395 +// { dg-do compile { target c++26 } } +// { dg-additional-options "-fcontracts" } + +template<typename... Args> + void f (Args... args) + post (((args) && ...)) {} + +template void f<> (); + +extern template void f<int&, int> (int&, int); +// { dg-error "value parameter 'args#1' used in a postcondition must be const" "" { target *-*-* } 6 } -- 2.52.0