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

Reply via email to