On 8/21/26 8:01 AM, Waffl3x wrote:
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?

Just some nits:

-- 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.

As discussed, please rename more expressively; it's ok to end with the PR number, but start with an indication of what it's testing.
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;

The alignment of this initializer won't survive re-indentation without added parens, it turns into

      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;

Likewise, or you could use non_reference (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&);

Reply via email to