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