On Thursday, August 27th, 2026 at 6:40 PM, Jason Merrill <[email protected]> 
wrote:

> On 8/21/26 7:03 AM, Waffl3x wrote:
> > Bootstrapped and tested on x86_64-pc-linux-gnu, okay for trunk?
> >
> > -- 8< --
> >
> > Empty packs were not being handled correctly, but merely terminating the
> > loop fails to handle a number of edge cases.  This patch instead skips
> > each expanded element before moving on to the next parameter to ensure
> > parameters that correspond to each other are compared.  It is unclear if
> > merely skipping pack elements is correct but it's probably the best thing
> > that can be done right now.  We certainly can't test them conditionally on
> > if the pack was used in a post condtion, as that would reject valid uses
> > of a pack index in a post condition.
> >
> >     PR c++/124395
> >     PR c++/126837
> >
> > gcc/cp/ChangeLog:
> >
> >     * contracts.cc (check_postconditions_in_redecl): Skip packs.
> >
> > gcc/testsuite/ChangeLog:
> >
> >     * g++.dg/contracts/cpp26/pr124395.C: New test.
> >     * g++.dg/contracts/cpp26/pr126837.C: New test.
> >
> > Signed-off-by: Waffl3x <[email protected]>
> > ---
> >   gcc/cp/contracts.cc                           | 28 +++++++++++++++++++
> >   .../g++.dg/contracts/cpp26/pr124395.C         |  8 ++++++
> >   .../g++.dg/contracts/cpp26/pr126837.C         |  9 ++++++
> >   3 files changed, 45 insertions(+)
> >   create mode 100644 gcc/testsuite/g++.dg/contracts/cpp26/pr124395.C
> >   create mode 100644 gcc/testsuite/g++.dg/contracts/cpp26/pr126837.C
> >
> > diff --git a/gcc/cp/contracts.cc b/gcc/cp/contracts.cc
> > index 25da963d0b4..7ca35184f30 100644
> > --- a/gcc/cp/contracts.cc
> > +++ b/gcc/cp/contracts.cc
> > @@ -585,6 +585,34 @@ check_postconditions_in_redecl (tree olddecl, tree 
> > newdecl)
> >     for (; t1 && t1 != void_list_node;
> >          t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2))
> >       {
> > +      if (DECL_PACK_P (t1))
> > +   {
> > +     /* Expanded params are checked in check_param_in_postcondition.  */
> > +     if (TREE_CHAIN (t1) == NULL_TREE
> > +         || TREE_CHAIN (t1) == void_list_node)
> > +       break;
> > +     /* Skip params that come from t1, we can't diagnose them here as they
> > +        might be indexed with a pack index.  */
> > +     const char *const pack_name = IDENTIFIER_POINTER (DECL_NAME (t1));
> > +     const size_t pack_name_len = IDENTIFIER_LENGTH (DECL_NAME (t1));
> > +     const auto parm_is_expanded_from_pack = [&] (const_tree expanded_id)
> > +       {
> > +         gcc_assert (TREE_CODE (expanded_id) == IDENTIFIER_NODE);
> > +         /* Expanded pack elements have #number added to their name.  */
> > +         if (!(IDENTIFIER_LENGTH (expanded_id) >= pack_name_len + 2u))
> > +           return false;
> > +         const char *const exp_name = IDENTIFIER_POINTER (expanded_id);
> > +         if (strncmp (pack_name, exp_name, pack_name_len) != 0)
> > +           return false;
> > +         return exp_name[pack_name_len] == '#';
> > +       };
> 
> Can't you use function_parameter_expanded_from_pack_p?

If it didn't work I could pretend I tried it :). Jokes aside, I was
hoping this did exist and couldn't find it, I'm relieved that it does.
Will fix.

> 
> > +     /* Stop one node early so continuing works.  */
> > +     if (parm_is_expanded_from_pack (DECL_NAME (t2)))
> > +       while (parm_is_expanded_from_pack (DECL_NAME (TREE_CHAIN (t2))))
> > +         t2 = TREE_CHAIN (t2);
> > +     /* Keep going to check params after the pack.  */
> > +     continue;
> > +   }
> >         if (parm_used_in_post_p (t1))
> >     {
> >       set_parm_used_in_post (t2);
> > 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..29926a55685
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/contracts/cpp26/pr124395.C
> > @@ -0,0 +1,8 @@
> > +// PR c++/124395
> > +// { dg-do compile { target c++26 } }
> > +// { dg-additional-options "-fcontracts" }
> > +
> > +template <typename... Ts>
> > +void f(Ts...) pre(true) {}
> > +
> > +template void f<>();
> > diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/pr126837.C 
> > b/gcc/testsuite/g++.dg/contracts/cpp26/pr126837.C
> > new file mode 100644
> > index 00000000000..a7a2b4d1253
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/contracts/cpp26/pr126837.C
> > @@ -0,0 +1,9 @@
> > +// PR c++/126837
> > +// { dg-do compile { target c++26 } }
> > +// { dg-additional-options "-fcontracts" }
> > +
> > +template<typename... Args>
> > +void f(Args... args, int const a)
> > +  post(a) {}
> > +
> > +template void f<int, int>(int, int, int);
> 
> 

I will also rename the test cases as discussed in other threads.

Thanks for the review,
Alex

Reply via email to