[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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.