I'm a little unhappy with how inelegant this is, not sure it can be
much better though.

Bootstrapped and tested on x86_64-pc-linux-gnu, okay for trunk?

-- 8< --

This patch adds special handling for constification of a parameter pack of
reference type.  Packs are already handled by cp_build_qualified_type, but
not packs of reference type.  Adding this handling to that function is also
an option, but this functionality doesn't seem to be relevant to anything
besides constification in contract assertions.  There is also a question of
whether cp_build_qualified_type should be handling pack expansions at all.

        PR c++/126878

gcc/cp/ChangeLog:

        * contracts.cc (view_as_const): Special case TYPE_PACK_EXPANSION
        with REFERENCE_TYPE pattern.

gcc/testsuite/ChangeLog:

        * g++.dg/contracts/cpp26/pr126878.C: New test.

Signed-off-by: Waffl3x <[email protected]>
---
 gcc/cp/contracts.cc                             | 13 ++++++++++++-
 gcc/testsuite/g++.dg/contracts/cpp26/pr126878.C |  9 +++++++++
 2 files changed, 21 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/contracts/cpp26/pr126878.C

diff --git a/gcc/cp/contracts.cc b/gcc/cp/contracts.cc
index 7ca35184f30..8ffd7500245 100644
--- a/gcc/cp/contracts.cc
+++ b/gcc/cp/contracts.cc
@@ -486,11 +486,22 @@ view_as_const (tree decl)
       && !CP_TYPE_CONST_P (TREE_TYPE (decl)))
     {
       gcc_checking_assert (!contract_const_wrapper_p (decl));
-      tree ctype = TREE_TYPE (decl);
+      const tree type_or_pack = TREE_TYPE (decl);
+      const tree type_or_ref = TREE_CODE (type_or_pack) == TYPE_PACK_EXPANSION
+                              ? PACK_EXPANSION_PATTERN (type_or_pack)
+                              : type_or_pack;
+      tree ctype = TYPE_REF_P (type_or_ref) ? TREE_TYPE (type_or_ref)
+                                           : type_or_ref;
+
       location_t loc =
          EXPR_P (decl) ? EXPR_LOCATION (decl) : DECL_SOURCE_LOCATION (decl);
       ctype = cp_build_qualified_type (ctype, (cp_type_quals (ctype)
                                               | TYPE_QUAL_CONST));
+      if (TYPE_REF_P (type_or_ref))
+       ctype = cp_build_reference_type (ctype,
+                                        TYPE_REF_IS_RVALUE (type_or_ref));
+      if (TREE_CODE (type_or_pack) == TYPE_PACK_EXPANSION)
+       ctype = make_pack_expansion (ctype);
       decl = build1 (VIEW_CONVERT_EXPR, ctype, decl);
       SET_EXPR_LOCATION (decl, loc);
       /* Mark the VCE as contract const wrapper.  */
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/pr126878.C 
b/gcc/testsuite/g++.dg/contracts/cpp26/pr126878.C
new file mode 100644
index 00000000000..01a42a88b92
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/pr126878.C
@@ -0,0 +1,9 @@
+// PR c++/126878
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-fcontracts" }
+
+template<typename... Args>
+void f(Args&... args)
+  pre((... && args)) {}
+
+template void f<int>(int&);
-- 
2.55.0

Reply via email to