Re: [PATCH v2] libstdc++: Fix std::ranges::iota not included in numeric [PR108760]

2024-05-23 Thread Patrick Palka
On Fri, 17 May 2024, Michael Levine (BLOOMBERG/ 731 LEX) wrote:

> This is the revised version of my patch incorporating the provided feedback 
> from Patrick Palka and Jonathan Wakely.
> This patch fixes GCC Bug 108760: 
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108760
> I moved out_value_result to , moved std::ranges:iota 
> into , removed my new test, and moved and renamed the existing test.

Nice, thanks!  The incremental changes seem good, but could you send a
single squashed patch containing all the changes?  That's what we'll end
up pushing after all.

> 
> I built my local version of gcc using the following configuration: $ 
> ../gcc/configure --disable-bootstrap --prefix="$(pwd)/_pfx/" 
> --enable-languages=c,c++,lto
> I then ran $ make -jN
> and $ make -jN install
> 
> Using the locally installed version, the following code compiled: 
> https://godbolt.org/z/33EPeqd1b
> 
> I tested my changes by running: $ make check-c++ -jN -k
> I personally found it difficult to understand the results of running the 
> tests.
> 
> I ran this on the following OS:
> 
> Virtualization: wsl
> Operating System: Ubuntu 20.04.6 LTS
> Kernel: Linux 5.15.146.1-microsoft-standard-WSL2
> Architecture: x86-64
> 
> 
> 
> From: Michael Levine (BLOOMBERG/ 731 LEX) At: 04/17/24 14:24:24 UTC-4:00
> To: libstd...@gcc.gnu.org, gcc-patches@gcc.gnu.org
> Subject: [PATCH] libstdc++: Fix std::ranges::iota is not included in numeric 
> [PR108760]
> 
> This patch fixes GCC Bug 108760: 
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108760
> Before this patch, using std::ranges::iota required including  
> when it should have been sufficient to only include .
> 
> When the patch is applied, the following code will compile: 
> https://godbolt.org/z/33EPeqd1b
> 
> I added a test case for this change as well.
> 
> I built my local version of gcc using the following configuration: $ 
> ../gcc/configure --disable-bootstrap --prefix="$(pwd)/_pfx/" 
> --enable-languages=c,c++,lto
> 
> and I tested my changes by running: $ make check-c++ -jN -k
> 
> I ran this on the following OS:
> 
> Virtualization: wsl
> Operating System: Ubuntu 20.04.6 LTS
> Kernel: Linux 5.15.146.1-microsoft-standard-WSL2
> Architecture: x86-64
> 
> 
> 
> 
> 



Re: [PATCH][14 backport] c++: Fix instantiation of imported temploid friends [PR114275]

2024-05-23 Thread Patrick Palka
 * g++.dg/modules/tpl-friend-12_f.C: New test.
>   * g++.dg/modules/tpl-friend-13_a.C: New test.
>   * g++.dg/modules/tpl-friend-13_b.C: New test.
>   * g++.dg/modules/tpl-friend-13_c.C: New test.
>   * g++.dg/modules/tpl-friend-13_d.C: New test.
>   * g++.dg/modules/tpl-friend-13_e.C: New test.
>   * g++.dg/modules/tpl-friend-13_f.C: New test.
>   * g++.dg/modules/tpl-friend-13_g.C: New test.
>   * g++.dg/modules/tpl-friend-14_a.C: New test.
>   * g++.dg/modules/tpl-friend-14_b.C: New test.
>   * g++.dg/modules/tpl-friend-14_c.C: New test.
>   * g++.dg/modules/tpl-friend-14_d.C: New test.
>   * g++.dg/modules/tpl-friend-9.C: New test.
> 
> Signed-off-by: Nathaniel Shead 
> Reviewed-by: Jason Merrill 
> Reviewed-by: Patrick Palka 
> ---
>  gcc/cp/cp-tree.h  |  3 +
>  gcc/cp/decl.cc| 41 ++
>  gcc/cp/module.cc  | 75 +++
>  gcc/cp/name-lookup.cc | 53 +
>  gcc/cp/pt.cc  | 32 +++-
>  .../g++.dg/modules/tpl-friend-10_a.C  | 15 
>  .../g++.dg/modules/tpl-friend-10_b.C  |  5 ++
>  .../g++.dg/modules/tpl-friend-10_c.C  |  7 ++
>  .../g++.dg/modules/tpl-friend-10_d.C  |  8 ++
>  .../g++.dg/modules/tpl-friend-11_a.C  | 14 
>  .../g++.dg/modules/tpl-friend-11_b.C  |  5 ++
>  .../g++.dg/modules/tpl-friend-12_a.C  | 10 +++
>  .../g++.dg/modules/tpl-friend-12_b.C  |  9 +++
>  .../g++.dg/modules/tpl-friend-12_c.C  | 10 +++
>  .../g++.dg/modules/tpl-friend-12_d.C  |  8 ++
>  .../g++.dg/modules/tpl-friend-12_e.C  |  7 ++
>  .../g++.dg/modules/tpl-friend-12_f.C  |  8 ++
>  .../g++.dg/modules/tpl-friend-13_a.C  | 13 
>  .../g++.dg/modules/tpl-friend-13_b.C  | 11 +++
>  .../g++.dg/modules/tpl-friend-13_c.C  | 13 
>  .../g++.dg/modules/tpl-friend-13_d.C  |  7 ++
>  .../g++.dg/modules/tpl-friend-13_e.C  | 18 +
>  .../g++.dg/modules/tpl-friend-13_f.C  |  7 ++
>  .../g++.dg/modules/tpl-friend-13_g.C  | 11 +++
>  .../g++.dg/modules/tpl-friend-14_a.C  |  8 ++
>  .../g++.dg/modules/tpl-friend-14_b.C  |  8 ++
>  .../g++.dg/modules/tpl-friend-14_c.C  |  7 ++
>  .../g++.dg/modules/tpl-friend-14_d.C  |  9 +++
>  gcc/testsuite/g++.dg/modules/tpl-friend-9.C   | 13 
>  29 files changed, 418 insertions(+), 17 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-10_a.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-10_b.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-10_c.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-10_d.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-11_a.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-11_b.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-12_a.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-12_b.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-12_c.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-12_d.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-12_e.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-12_f.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-13_a.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-13_b.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-13_c.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-13_d.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-13_e.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-13_f.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-13_g.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-14_a.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-14_b.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-14_c.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-14_d.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-9.C
> 
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 9975dc78456..0c14241fce7 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -7417,6 +7417,8 @@ extern unsigned get_importing_module (tree, bool = 
> false) ATTRIBUTE_PURE;
>  extern void set_instantiating_module (tree);
>  extern void set_defining_module (tree);
>  extern void maybe_key_decl (tree ctx, tree decl);
> +extern void propagate_defining_module (tree decl, tree orig);
> +extern void remove_defining_module (tree decl);
>  
>  extern void man

Re: [PATCH v26 01/13] libstdc++: Optimize std::is_const compilation performance

2024-05-23 Thread Patrick Palka
On Sat, 11 May 2024, Ken Matsui wrote:

> This patch optimizes the compilation performance of std::is_const
> by dispatching to the new __is_const built-in trait.

This patch series LGTM

> 
> libstdc++-v3/ChangeLog:
> 
>   * include/std/type_traits (is_const): Use __is_const built-in
>   trait.
>   (is_const_v): Likewise.
> 
> Signed-off-by: Ken Matsui 
> ---
>  libstdc++-v3/include/std/type_traits | 12 
>  1 file changed, 12 insertions(+)
> 
> diff --git a/libstdc++-v3/include/std/type_traits 
> b/libstdc++-v3/include/std/type_traits
> index b441bf9908f..8df0cf3ac3b 100644
> --- a/libstdc++-v3/include/std/type_traits
> +++ b/libstdc++-v3/include/std/type_traits
> @@ -835,6 +835,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>// Type properties.
>  
>/// is_const
> +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
> +  template
> +struct is_const
> +: public __bool_constant<__is_const(_Tp)>
> +{ };
> +#else
>template
>  struct is_const
>  : public false_type { };
> @@ -842,6 +848,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>template
>  struct is_const<_Tp const>
>  : public true_type { };
> +#endif
>  
>/// is_volatile
>template
> @@ -3331,10 +3338,15 @@ template 
>inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value;
>  #endif
>  
> +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
> +template 
> +  inline constexpr bool is_const_v = __is_const(_Tp);
> +#else
>  template 
>inline constexpr bool is_const_v = false;
>  template 
>inline constexpr bool is_const_v = true;
> +#endif
>  
>  #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function)
>  template 
> -- 
> 2.44.0
> 
> 



Re: [PATCH] libstdc++: Implement ranges::concat_view from P2542R7

2024-05-23 Thread Patrick Palka
On Mon, 29 Apr 2024, Jonathan Wakely wrote:

> On Mon, 22 Apr 2024 at 22:43, Patrick Palka wrote:
> >
> > Tested on x86_64-pc-linux-gnu, does this look OK for trunk?  More tests
> > are needed but I figured I'd submit this now for possible consideration into
> > GCC 14 since we're getting close to release..  All changes are confined to
> > C++26.
> 
> OK for trunk. Maybe we can backport it for 14.2 later, but not now.
> Sorry for the review being slow.

No worries, thanks a lot!  I pushed this now, though I realized I didn't
implement the latest/approved revision of the paper, R8 vs R7, which
notably changes the constraints on operator-(it, default_sentinel).
Since that seems to be the only significant change, I reckon I'll fix
that in a follow-up patch.

> 
> 
> >
> > -- >8 --
> >
> > libstdc++-v3/ChangeLog:
> >
> > * include/bits/version.def (ranges_concat): Define.
> > * include/bits/version.h: Regenerate.
> > * include/std/ranges (__detail::__concat_reference_t): Define
> > for C++26.
> > (__detail::__concat_value_t): Likewise.
> > (__detail::__concat_rvalue_reference_t): Likewise.
> > (__detail::__concat_indirectly_readable_impl): Likewise.
> > (__detail::__concat_indirectly_readable): Likewise.
> > (__detail::__concatable): Likewise.
> > (__detail::__all_but_last_common): Likewise.
> > (__detail::__concat_is_random_access): Likewise.
> > (__detail::__concat_is_bidirectional): Likewise.
> > (__detail::__last_is_common): Likewise.
> > (concat_view): Likewise.
> > (__detail::__concat_view_iter_cat): Likewise.
> > (concat_view::iterator): Likewise.
> > (views::__detail::__can_concat_view): Likewise.
> > (views::_Concat, views::concat): Likewise.
> > * testsuite/std/ranges/concat/1.cc: New test.
> > ---
> >  libstdc++-v3/include/bits/version.def |   8 +
> >  libstdc++-v3/include/bits/version.h   |  10 +
> >  libstdc++-v3/include/std/ranges   | 584 ++
> >  libstdc++-v3/testsuite/std/ranges/concat/1.cc |  61 ++
> >  4 files changed, 663 insertions(+)
> >  create mode 100644 libstdc++-v3/testsuite/std/ranges/concat/1.cc
> >
> > diff --git a/libstdc++-v3/include/bits/version.def 
> > b/libstdc++-v3/include/bits/version.def
> > index 5c0477fb61e..af13090c094 100644
> > --- a/libstdc++-v3/include/bits/version.def
> > +++ b/libstdc++-v3/include/bits/version.def
> > @@ -1796,6 +1796,14 @@ ftms = {
> >};
> >  };
> >
> > +ftms = {
> > +  name = ranges_concat;
> > +  values = {
> > +v = 202403;
> > +cxxmin = 26;
> > +  };
> > +};
> > +
> >  // Standard test specifications.
> >  stds[97] = ">= 199711L";
> >  stds[03] = ">= 199711L";
> > diff --git a/libstdc++-v3/include/bits/version.h 
> > b/libstdc++-v3/include/bits/version.h
> > index 65e708c73fb..1f27bfe050d 100644
> > --- a/libstdc++-v3/include/bits/version.h
> > +++ b/libstdc++-v3/include/bits/version.h
> > @@ -2003,4 +2003,14 @@
> >  #endif /* !defined(__cpp_lib_to_string) && 
> > defined(__glibcxx_want_to_string) */
> >  #undef __glibcxx_want_to_string
> >
> > +#if !defined(__cpp_lib_ranges_concat)
> > +# if (__cplusplus >  202302L)
> > +#  define __glibcxx_ranges_concat 202403L
> > +#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges_concat)
> > +#   define __cpp_lib_ranges_concat 202403L
> > +#  endif
> > +# endif
> > +#endif /* !defined(__cpp_lib_ranges_concat) && 
> > defined(__glibcxx_want_ranges_concat) */
> > +#undef __glibcxx_want_ranges_concat
> > +
> >  #undef __glibcxx_want_all
> > diff --git a/libstdc++-v3/include/std/ranges 
> > b/libstdc++-v3/include/std/ranges
> > index afce818376b..28a39bf6f34 100644
> > --- a/libstdc++-v3/include/std/ranges
> > +++ b/libstdc++-v3/include/std/ranges
> > @@ -55,6 +55,7 @@
> >  #define __glibcxx_want_ranges_as_const
> >  #define __glibcxx_want_ranges_as_rvalue
> >  #define __glibcxx_want_ranges_cartesian_product
> > +#define __glibcxx_want_ranges_concat
> >  #define __glibcxx_want_ranges_chunk
> >  #define __glibcxx_want_ranges_chunk_by
> >  #define __glibcxx_want_ranges_enumerate
> > @@ -9514,6 +9515,589 @@ namespace __detail
> >  } // namespace ranges
> >  #endif // __cpp_lib_ranges_to_container
> >
> > +#if __cpp_lib_ranges_concat // C++ >= C+

Re: [PATCH] c++: alias CTAD and copy deduction guide [PR115198]

2024-05-23 Thread Patrick Palka
On Thu, 23 May 2024, Jason Merrill wrote:

> On 5/23/24 14:06, Patrick Palka wrote:
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> > OK for trunk/14?
> > 
> > -- >8 --
> > 
> > Here we're neglecting to update DECL_NAME during the alias CTAD guide
> > transformation, which causes copy_guide_p to return false for the
> > transformed copy deduction guide since DECL_NAME is still __dguide_C
> > with TREE_TYPE C but it should be __dguide_A with TREE_TYPE A
> > (equivalently C).  This ultimately results in ambiguity during
> > overload resolution between the copy deduction guide vs copy ctor guide.
> > 
> > This patch makes us update DECL_NAME of a transformed guide accordingly
> > during alias CTAD.  This eventually needs to be done for inherited CTAD
> > too, but it's not clear what identifier to use there since it has to be
> > unique for each derived/base pair.  For
> > 
> >template struct A { ... };
> >template struct B : A { using A::A; }
> > 
> > at first glance it'd be reasonable to give inherited guides a name of
> > __dguide_B with TREE_TYPE A, but since that name is already
> > used B's own guides its TREE_TYPE is already B.
> 
> Why can't it be the same __dguide_B with TREE_TYPE B?

Ah because copy_guide_p relies on TREE_TYPE in order to recognize a copy
deduction guide, and with that TREE_TYPE it would still incorrectly
return false for an inherited copy deduction guide, e.g.

  A(A) -> A

gets transformed into

  B(A) -> B

and A != B so copy_guide_p returns false.

But it just occurred to me that this TREE_TYPE clobbering of the
__dguide_foo identifier already happens if we have two class templates
with the same name in different namespaces, since the identifier
contains only the terminal name.  Maybe this suggests that we should
use a tree flag to track whether a guide is the copy deduction guide
instead of setting TREE_TYPE of DECL_NAME?

> 
> > PR c++/115198
> > 
> > gcc/cp/ChangeLog:
> > 
> > * pt.cc (alias_ctad_tweaks): Update DECL_NAME of a transformed
> > guide during alias CTAD.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/cpp2a/class-deduction-alias22.C: New test.
> > ---
> >   gcc/cp/pt.cc   |  9 -
> >   .../g++.dg/cpp2a/class-deduction-alias22.C | 14 ++
> >   2 files changed, 22 insertions(+), 1 deletion(-)
> >   create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-alias22.C
> > 
> > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > index 0c4d96cf768..58873057abc 100644
> > --- a/gcc/cp/pt.cc
> > +++ b/gcc/cp/pt.cc
> > @@ -30304,13 +30304,14 @@ alias_ctad_tweaks (tree tmpl, tree uguides)
> >any).  */
> >   enum { alias, inherited } ctad_kind;
> > -  tree atype, fullatparms, utype;
> > +  tree atype, fullatparms, utype, name;
> > if (TREE_CODE (tmpl) == TEMPLATE_DECL)
> >   {
> > ctad_kind = alias;
> > atype = TREE_TYPE (tmpl);
> > fullatparms = DECL_TEMPLATE_PARMS (tmpl);
> > utype = DECL_ORIGINAL_TYPE (DECL_TEMPLATE_RESULT (tmpl));
> > +  name = dguide_name (tmpl);
> >   }
> > else
> >   {
> > @@ -30318,6 +30319,10 @@ alias_ctad_tweaks (tree tmpl, tree uguides)
> > atype = NULL_TREE;
> > fullatparms = TREE_PURPOSE (tmpl);
> > utype = TREE_VALUE (tmpl);
> > +  /* FIXME: What name should we give inherited guides?  It needs to be
> > +unique to the derived/base pair so that we don't clobber an earlier
> > +setting of TREE_TYPE.  */
> > +  name = NULL_TREE;
> >   }
> >   tsubst_flags_t complain = tf_warning_or_error;
> > @@ -30413,6 +30418,8 @@ alias_ctad_tweaks (tree tmpl, tree uguides)
> > }
> >   if (g == error_mark_node)
> > continue;
> > + if (name)
> > +   DECL_NAME (g) = name;
> >   if (nfparms == 0)
> > {
> >   /* The targs are all non-dependent, so g isn't a template.  */
> > diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias22.C
> > b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias22.C
> > new file mode 100644
> > index 000..9c6c841166a
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias22.C
> > @@ -0,0 +1,14 @@
> > +// PR c++/115198
> > +// { dg-do compile { target c++20 } }
> > +
> > +template
> > +struct C {
> > +  C() = default;
> > +  C(const C&) = default;
> > +};
> > +
> > +template
> > +using A = C;
> > +
> > +C c;
> > +A a = c; // { dg-bogus "ambiguous" }
> 
> 



[PATCH] c++: alias CTAD and copy deduction guide [PR115198]

2024-05-23 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
OK for trunk/14?

-- >8 --

Here we're neglecting to update DECL_NAME during the alias CTAD guide
transformation, which causes copy_guide_p to return false for the
transformed copy deduction guide since DECL_NAME is still __dguide_C
with TREE_TYPE C but it should be __dguide_A with TREE_TYPE A
(equivalently C).  This ultimately results in ambiguity during
overload resolution between the copy deduction guide vs copy ctor guide.

This patch makes us update DECL_NAME of a transformed guide accordingly
during alias CTAD.  This eventually needs to be done for inherited CTAD
too, but it's not clear what identifier to use there since it has to be
unique for each derived/base pair.  For

  template struct A { ... };
  template struct B : A { using A::A; }

at first glance it'd be reasonable to give inherited guides a name of
__dguide_B with TREE_TYPE A, but since that name is already
used B's own guides its TREE_TYPE is already B.

PR c++/115198

gcc/cp/ChangeLog:

* pt.cc (alias_ctad_tweaks): Update DECL_NAME of a transformed
guide during alias CTAD.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/class-deduction-alias22.C: New test.
---
 gcc/cp/pt.cc   |  9 -
 .../g++.dg/cpp2a/class-deduction-alias22.C | 14 ++
 2 files changed, 22 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-alias22.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 0c4d96cf768..58873057abc 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -30304,13 +30304,14 @@ alias_ctad_tweaks (tree tmpl, tree uguides)
  any).  */
 
   enum { alias, inherited } ctad_kind;
-  tree atype, fullatparms, utype;
+  tree atype, fullatparms, utype, name;
   if (TREE_CODE (tmpl) == TEMPLATE_DECL)
 {
   ctad_kind = alias;
   atype = TREE_TYPE (tmpl);
   fullatparms = DECL_TEMPLATE_PARMS (tmpl);
   utype = DECL_ORIGINAL_TYPE (DECL_TEMPLATE_RESULT (tmpl));
+  name = dguide_name (tmpl);
 }
   else
 {
@@ -30318,6 +30319,10 @@ alias_ctad_tweaks (tree tmpl, tree uguides)
   atype = NULL_TREE;
   fullatparms = TREE_PURPOSE (tmpl);
   utype = TREE_VALUE (tmpl);
+  /* FIXME: What name should we give inherited guides?  It needs to be
+unique to the derived/base pair so that we don't clobber an earlier
+setting of TREE_TYPE.  */
+  name = NULL_TREE;
 }
 
   tsubst_flags_t complain = tf_warning_or_error;
@@ -30413,6 +30418,8 @@ alias_ctad_tweaks (tree tmpl, tree uguides)
}
  if (g == error_mark_node)
continue;
+ if (name)
+   DECL_NAME (g) = name;
  if (nfparms == 0)
{
  /* The targs are all non-dependent, so g isn't a template.  */
diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias22.C 
b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias22.C
new file mode 100644
index 000..9c6c841166a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias22.C
@@ -0,0 +1,14 @@
+// PR c++/115198
+// { dg-do compile { target c++20 } }
+
+template
+struct C {
+  C() = default;
+  C(const C&) = default;
+};
+
+template
+using A = C;
+
+C c;
+A a = c; // { dg-bogus "ambiguous" }
-- 
2.45.1.216.g4365c6fcf9



Re: [PATCH] Fix auto deduction for template specialization scopes [114915].

2024-05-22 Thread Patrick Palka
On Wed, 22 May 2024, Jason Merrill wrote:

> Thanks for the patch!
> 
> Please review https://gcc.gnu.org/contribute.html for more details of the
> format patches should have.  In particular, you don't seem to have a copyright
> assignment on file with the FSF, so you'll need to either do that or certify
> that the contribution is under the DCO.
> 
> Also, you need a component tag (c++:) in the subject line, and ChangeLog
> entries in the commit message.  Note what contribute.html says about git
> gcc-commit-mklog, which makes that a lot simpler.
> 
> On 5/1/24 18:52, Seyed Sajad Kahani wrote:
> > When deducing auto for `adc_return_type`, `adc_variable_type`, and
> > `adc_decomp_type` contexts (at the usage time), we try to resolve the
> > outermost template arguments to be used for satisfaction. This is done by
> > one of the following, depending on the scope:
> > 
> > 1. Checking the `DECL_TEMPLATE_INFO` of the current function scope and
> > extracting DECL_TI_ARGS from it for function scope deductions (pt.cc:31236).
> > 2. Checking the `DECL_TEMPLATE_INFO` of the declaration (alongside with
> > other conditions) for non-function scope variable declaration deductions
> > (decl.cc:8527).
> > 
> > Then, we do not retrieve the deeper layers of the template arguments;
> > instead, we fill the missing levels with dummy levels (pt.cc:31260).
> > 
> > The problem (that is shown in PR114915) is that we do not consider the case
> > where the deduction happens in a template specialization scope. In this
> > case, the type is not dependent on the outermost template arguments (which
> > are the specialization arguments). Yet, we still resolve the outermost
> > template arguments, and then the number of layers in the template arguments
> > exceeds the number of levels in the type. This causes the missing levels to
> > be negative. This leads to the rejection of valid code and ICEs (like
> > segfault) in the release mode. In the debug mode, it is possible to show as
> > an assertion failure (when creating a tree_vec with a negative size).
> > The code that generates the issue is added to the test suite as
> > `g++.dg/cpp2a/concepts-placeholder14.C`.
> 
> This testcase could use more cases, like variable template specialization
> (both full and partial) and member functions where not all enclosing classes
> are fully specialized.

Note I think the latest version of the patch is
https://gcc.gnu.org/pipermail/gcc-patches/2024-May/651805.html
which has more test coverage and takes a more context oblivious approach
that keeps the innermost arguments if there's an excess, based on some
earlier discussion e.g.
https://gcc.gnu.org/pipermail/gcc-patches/2024-May/650834.html
This should do the right thing at least until we implement explicit
specializations in template scope (CWG 727)

> 
> > This patch fixes the issue by checking that the template usage, whose
> > arguments are going to be used for satisfaction, is not a partial or
> > explicit specialization (and therefore it is an implicit or explicit
> > instantiation). This check is done in the two only places that affect the
> > `outer_targs` for the mentioned contexts.
> 
> It seems like we want a function to use instead of DECL_TI_ARGS to get the
> args for parameters that are actually in scope in the definition that we're
> substituting into.  In the case of a full specialization, that would be
> NULL_TREE, but it's more complicated for partial specializations.
> 
> This function should probably go after outer_template_args in pt.cc.
> 
> > One might ask why this is not implemented as a simple `missing_level > 0`
> > check. The reason is that the recovery from the negative `missing_levels`
> > will not be easy, and it is not clear how to recover from it. Therefore, it
> > is better to prevent it from happening.
> 
> But you still have that check in the patch.  Would it be better as an assert?
> 
> Thanks,
> Jason
> 
> 



Re: [PATCH] c++: canonicity of fn types w/ complex eh specs [PR115159]

2024-05-22 Thread Patrick Palka
On Tue, 21 May 2024, Jason Merrill wrote:

> On 5/21/24 21:55, Patrick Palka wrote:
> > On Tue, 21 May 2024, Jason Merrill wrote:
> > 
> > > On 5/21/24 17:27, Patrick Palka wrote:
> > > > On Tue, 21 May 2024, Jason Merrill wrote:
> > > > 
> > > > > On 5/21/24 15:36, Patrick Palka wrote:
> > > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> > > > > > OK for trunk?
> > > > > > 
> > > > > > Alternatively, I considered fixing this by incrementing
> > > > > > comparing_specializations around the call to comp_except_specs in
> > > > > > cp_check_qualified_type, but generally for types whose identity
> > > > > > depends on whether comparing_specializations is set we need to
> > > > > > use structural equality anyway IIUC.
> > > > > 
> > > > > Why not both?
> > > > 
> > > > I figured the latter change isn't necessary/observable since
> > > > comparing_specializations would only make a difference for complex
> > > > exception specifications, and with this patch we won't even call
> > > > cp_check_qualified_type on a complex eh spec.
> > > 
> > > My concern is that if we're building a function type multiple times with
> > > the
> > > same noexcept-spec, this patch would mean creating multiple equivalent
> > > function types instead of reusing one already created for the same
> > > function.
> > > 
> > > > > > +  bool complex_p = (cr && cr != noexcept_true_spec
> > > > > > +   && !UNPARSED_NOEXCEPT_SPEC_P (cr));
> > > > > 
> > > > > Why treat unparsed specs differently from parsed ones?
> > > > 
> > > > Unparsed specs are unique according to cp_tree_equal, so in turn
> > > > function types with unparsed specs are unique, so it should be safe to
> > > > treat such types as canonical.  I'm not sure if this optimization
> > > > matters though; I'm happy to remove this case.
> > > 
> > > The idea that this optimization could make a difference raised the concern
> > > above.
> > 
> > Aha, makes sense.  To that end it seems we could strengthen the ce_exact
> > in comp_except_specs to require == instead of cp_tree_equal equality
> > when comparing two noexcept-specs; the only ce_exact callers are
> > cp_check_qualified_type and cxx_type_hash_eq, which should be fine with
> > that strengthening.  This way, we at least do try to reuse a variant if
> > the (complex or unparsed) noexcept-spec is exactly the same.
> 
> Sounds good.
> 
> Given that, we probably still want to move the canonical_eh_spec up in
> build_cp_fntype_variant, and pass that to cp_check_qualified_type?

And compare the canonical spec directly from cp_check_qualified_type
instead of using comp_except_specs?  Then IIUC for

  void f() throw(int);
  void g() throw(char);

we'd give g the same function type as f, which seems wrong?


> 
> > Like so?
> > 
> > -- >8 --
> > 
> > Subject: [PATCH] c++: canonicity of fn types w/ complex eh specs [PR115159]
> > 
> > Here the member functions QList::g and QList::h are given the same
> > function type since their exception specifications are equivalent
> > according to cp_tree_equal.  In doing so however this means that the
> > type of QList::h refers to a function parameter from QList::g, which
> > ends up confusing modules streaming.
> > 
> > I'm not sure if modules can be fixed to handle this situation, but
> > regardless it seems weird in principle that a function parameter can
> > escape in such a way.  The analogous situation with a trailing return
> > type and decltype
> > 
> >auto g(QList ) -> decltype(f(other));
> >auto h(QList ) -> decltype(f(other));
> > 
> > behaves better because we don't canonicalize decltype, and so the
> > function types of g and h are non-canonical and therefore not shared.
> > 
> > In light of this, it seems natural to treat function types with complex
> > eh specs as non-canonical as well so that each such function declaration
> > is given a unique function/method type node.  The main benefit of type
> > canonicalization is to speed up repeated type comparisons, but it should
> > rare for us to repeatedly compare two otherwise compatible function
> > types with complex exception specifications, so foregoing canonicalization
> > should not cause any problems.
> > 
&

Re: [PATCH] c++: canonicity of fn types w/ complex eh specs [PR115159]

2024-05-21 Thread Patrick Palka
On Tue, 21 May 2024, Jason Merrill wrote:

> On 5/21/24 17:27, Patrick Palka wrote:
> > On Tue, 21 May 2024, Jason Merrill wrote:
> > 
> > > On 5/21/24 15:36, Patrick Palka wrote:
> > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> > > > OK for trunk?
> > > > 
> > > > Alternatively, I considered fixing this by incrementing
> > > > comparing_specializations around the call to comp_except_specs in
> > > > cp_check_qualified_type, but generally for types whose identity
> > > > depends on whether comparing_specializations is set we need to
> > > > use structural equality anyway IIUC.
> > > 
> > > Why not both?
> > 
> > I figured the latter change isn't necessary/observable since
> > comparing_specializations would only make a difference for complex
> > exception specifications, and with this patch we won't even call
> > cp_check_qualified_type on a complex eh spec.
> 
> My concern is that if we're building a function type multiple times with the
> same noexcept-spec, this patch would mean creating multiple equivalent
> function types instead of reusing one already created for the same function.
> 
> > > > +  bool complex_p = (cr && cr != noexcept_true_spec
> > > > +   && !UNPARSED_NOEXCEPT_SPEC_P (cr));
> > > 
> > > Why treat unparsed specs differently from parsed ones?
> > 
> > Unparsed specs are unique according to cp_tree_equal, so in turn
> > function types with unparsed specs are unique, so it should be safe to
> > treat such types as canonical.  I'm not sure if this optimization
> > matters though; I'm happy to remove this case.
> 
> The idea that this optimization could make a difference raised the concern
> above.

Aha, makes sense.  To that end it seems we could strengthen the ce_exact
in comp_except_specs to require == instead of cp_tree_equal equality
when comparing two noexcept-specs; the only ce_exact callers are
cp_check_qualified_type and cxx_type_hash_eq, which should be fine with
that strengthening.  This way, we at least do try to reuse a variant if
the (complex or unparsed) noexcept-spec is exactly the same.

Like so?

-- >8 --

Subject: [PATCH] c++: canonicity of fn types w/ complex eh specs [PR115159]

Here the member functions QList::g and QList::h are given the same
function type since their exception specifications are equivalent
according to cp_tree_equal.  In doing so however this means that the
type of QList::h refers to a function parameter from QList::g, which
ends up confusing modules streaming.

I'm not sure if modules can be fixed to handle this situation, but
regardless it seems weird in principle that a function parameter can
escape in such a way.  The analogous situation with a trailing return
type and decltype

  auto g(QList ) -> decltype(f(other));
  auto h(QList ) -> decltype(f(other));

behaves better because we don't canonicalize decltype, and so the
function types of g and h are non-canonical and therefore not shared.

In light of this, it seems natural to treat function types with complex
eh specs as non-canonical as well so that each such function declaration
is given a unique function/method type node.  The main benefit of type
canonicalization is to speed up repeated type comparisons, but it should
rare for us to repeatedly compare two otherwise compatible function
types with complex exception specifications, so foregoing canonicalization
should not cause any problems.

To that end, this patch strengthens the ce_exact case of comp_except_specs
to require identity instead of equivalence of the exception specification
so that build_cp_fntype_variant doesn't reuse a variant when it shouldn't.
And in build_cp_fntype_variant we need to use structural equality for types
with a complex eh spec.  In turn we could simplify the code responsible
for adjusting unparsed eh spec variants.

PR c++/115159

gcc/cp/ChangeLog:

* tree.cc (build_cp_fntype_variant): Always use structural
equality for types with a complex exception specification.
(fixup_deferred_exception_variants): Always use structural
equality for adjusted variants.
* typeck.cc (comp_except_specs): Require == instead of
cp_tree_equal for noexcept-spec comparison in the ce_exact case.

gcc/testsuite/ChangeLog:

* g++.dg/modules/noexcept-2_a.H: New test.
* g++.dg/modules/noexcept-2_b.C: New test.
---
 gcc/cp/tree.cc  | 47 +
 gcc/cp/typeck.cc|  4 +-
 gcc/testsuite/g++.dg/modules/noexcept-2_a.H | 24 +++
 gcc/testsuite/g++.dg/modules/noexcept-2_b.C |  4 ++
 4 files changed, 41 insertions(+), 38 deletions(-)
 create mode 100644 gc

Re: [PATCH] c++: canonicity of fn types w/ complex eh specs [PR115159]

2024-05-21 Thread Patrick Palka
On Tue, 21 May 2024, Patrick Palka wrote:

> On Tue, 21 May 2024, Jason Merrill wrote:
> 
> > On 5/21/24 15:36, Patrick Palka wrote:
> > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> > > OK for trunk?
> > > 
> > > Alternatively, I considered fixing this by incrementing
> > > comparing_specializations around the call to comp_except_specs in
> > > cp_check_qualified_type, but generally for types whose identity
> > > depends on whether comparing_specializations is set we need to
> > > use structural equality anyway IIUC.
> > 
> > Why not both?
> 
> I figured the latter change isn't necessary/observable since
> comparing_specializations would only make a difference for complex
> exception specifications, and with this patch we won't even call
> cp_check_qualified_type on a complex eh spec.
> 
> > 
> > > +  bool complex_p = (cr && cr != noexcept_true_spec
> > > + && !UNPARSED_NOEXCEPT_SPEC_P (cr));
> > 
> > Why treat unparsed specs differently from parsed ones?
> 
> Unparsed specs are unique according to cp_tree_equal, so in turn
> function types with unparsed specs are unique, so it should be safe to
> treat such types as canonical.  I'm not sure if this optimization
> matters though; I'm happy to remove this case.

FWIW if we do get rid of this case then I think in
fixup_deferred_exception_variants we can assert TYPE_STRUCTURAL_EQUALITY_P
is already set instead of having to set it.

> 
> > 
> > Jason
> > 
> > 
> 



Re: [PATCH] c++: canonicity of fn types w/ complex eh specs [PR115159]

2024-05-21 Thread Patrick Palka
On Tue, 21 May 2024, Jason Merrill wrote:

> On 5/21/24 15:36, Patrick Palka wrote:
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> > OK for trunk?
> > 
> > Alternatively, I considered fixing this by incrementing
> > comparing_specializations around the call to comp_except_specs in
> > cp_check_qualified_type, but generally for types whose identity
> > depends on whether comparing_specializations is set we need to
> > use structural equality anyway IIUC.
> 
> Why not both?

I figured the latter change isn't necessary/observable since
comparing_specializations would only make a difference for complex
exception specifications, and with this patch we won't even call
cp_check_qualified_type on a complex eh spec.

> 
> > +  bool complex_p = (cr && cr != noexcept_true_spec
> > +   && !UNPARSED_NOEXCEPT_SPEC_P (cr));
> 
> Why treat unparsed specs differently from parsed ones?

Unparsed specs are unique according to cp_tree_equal, so in turn
function types with unparsed specs are unique, so it should be safe to
treat such types as canonical.  I'm not sure if this optimization
matters though; I'm happy to remove this case.

> 
> Jason
> 
> 



[PATCH] c++: canonicity of fn types w/ complex eh specs [PR115159]

2024-05-21 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
OK for trunk?

Alternatively, I considered fixing this by incrementing
comparing_specializations around the call to comp_except_specs in
cp_check_qualified_type, but generally for types whose identity
depends on whether comparing_specializations is set we need to
use structural equality anyway IIUC.

Or maybe it isn't right to fix this outside of modules, and we should
instead make modules cope with this cross-function function parameter
reference?  I briefly tried looking into this but didn't get very far.

-- >8 --

Here the member functions QList::g and QList::h are given the same
function type since their exception specifications are equivalent
according to cp_tree_equal.  In doing so however this means that the
type of QList::h refers to a function parameter from QList::g, which
ends up confusing modules streaming.

I'm not sure if modules can be fixed to handle this situation, but
regardless it seems weird in principle that a function parameter can
escape in such a way.  The analogous situation with a trailing return
type and decltype

  auto g(QList ) -> decltype(f(other));
  auto h(QList ) -> decltype(f(other));

behaves better because we don't canonicalize decltype, and so the
function types of g and h are non-canonical and therefore not shared.

In light of this, it seems natural to treat function types with complex
eh specs as non-canonical as well so that each such function declaration
is given a unique function/method type node.  The main benefit of type
canonicalization is to speed up repeated type comparisons, but it should
rare for us to repeatedly compare two otherwise compatible function
types with complex exception specifications, so foregoing canonicalization
should be harmless IIUC.  On the other hand this change simplifies the
code responsible for adjusting unparsed eh spec variants.

PR c++/115159

gcc/cp/ChangeLog:

* tree.cc (build_cp_fntype_variant): Don't reuse a variant with
a complex exception specification.  Always use structural
equality in that case.
(fixup_deferred_exception_variants): Always use structural
equality for adjusted variants.

gcc/testsuite/ChangeLog:

* g++.dg/modules/noexcept-2_a.H: New test.
* g++.dg/modules/noexcept-2_b.C: New test.
---
 gcc/cp/tree.cc  | 70 +++--
 gcc/testsuite/g++.dg/modules/noexcept-2_a.H | 24 +++
 gcc/testsuite/g++.dg/modules/noexcept-2_b.C |  4 ++
 3 files changed, 51 insertions(+), 47 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/modules/noexcept-2_a.H
 create mode 100644 gcc/testsuite/g++.dg/modules/noexcept-2_b.C

diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 9d37d255d8d..7987c01520d 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -2761,16 +2761,27 @@ build_cp_fntype_variant (tree type, cp_ref_qualifier 
rqual,
 {
   cp_cv_quals type_quals = TYPE_QUALS (type);
 
-  if (cp_check_qualified_type (type, type, type_quals, rqual, raises, late))
-return type;
+  /* Canonicalize the exception specification.  */
+  tree cr = flag_noexcept_type ? canonical_eh_spec (raises) : NULL_TREE;
+  /* For a complex exception specification, always create a distinct
+ non-canonical variant for simplicity.  This also prevents noexcept-specs
+ that are in terms of a function parameter from getting shared with an
+ another function.  */
+  bool complex_p = (cr && cr != noexcept_true_spec
+   && !UNPARSED_NOEXCEPT_SPEC_P (cr));
+  if (!complex_p)
+{
+  if (cp_check_qualified_type (type, type, type_quals, rqual, raises, 
late))
+   return type;
 
-  tree v = TYPE_MAIN_VARIANT (type);
-  for (; v; v = TYPE_NEXT_VARIANT (v))
-if (cp_check_qualified_type (v, type, type_quals, rqual, raises, late))
-  return v;
+  tree v = TYPE_MAIN_VARIANT (type);
+  for (; v; v = TYPE_NEXT_VARIANT (v))
+   if (cp_check_qualified_type (v, type, type_quals, rqual, raises, late))
+ return v;
+}
 
   /* Need to build a new variant.  */
-  v = build_variant_type_copy (type);
+  tree v = build_variant_type_copy (type);
   if (!TYPE_DEPENDENT_P (v))
 /* We no longer know that it's not type-dependent.  */
 TYPE_DEPENDENT_P_VALID (v) = false;
@@ -2791,10 +2802,7 @@ build_cp_fntype_variant (tree type, cp_ref_qualifier 
rqual,
   break;
 }
 
-  /* Canonicalize the exception specification.  */
-  tree cr = flag_noexcept_type ? canonical_eh_spec (raises) : NULL_TREE;
-
-  if (TYPE_STRUCTURAL_EQUALITY_P (type))
+  if (TYPE_STRUCTURAL_EQUALITY_P (type) || complex_p)
 /* Propagate structural equality. */
 SET_TYPE_STRUCTURAL_EQUALITY (v);
   else if (TYPE_CANONICAL (type) != type || cr != raises || late)
@@ -2812,55 +2820,23 @@ build_cp_fntype_variant (tree type, cp_ref_qualifier 
rqual,
 /* TYPE is a function or method type with a deferred exception
specification that has been parsed to RAISES.  

[PATCH] c++: folding non-dep enumerator from current inst [PR115139]

2024-05-17 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk/14?

-- >8 --

After the tsubst_copy removal r14-4796-g3e3d73ed5e85e7 GCC 14 ICEs during
fold_non_dependent_expr for 'e1 | e2' ultimately because we no longer exit
early when substituting the CONST_DECLs for e1 and e2 with args=NULL_TREE,
during which we try substituting the class context A (also with
args=NULL_TREE) which ends up ICEing from tsubst_pack_expansion (due to
processing_template_decl being cleared).

Incidentally, the ICE went away on trunk ever since the tsubst_aggr_type
removal r15-123-gf04dc89a991ddc since it made the CONST_DECL case of
tsubst_expr use tsubst to substitute the context, which does short circuit
for empty args and so avoids the ICE.

This patch fixes this ICE for GCC 14 by narrowly restoring the early exit
for empty args that was present in tsubst_copy when substituting an
enumerator CONST_DECL.  We might as well apply this to trunk too, as a
very minor optimization.

PR c++/115139

gcc/cp/ChangeLog:

* pt.cc (tsubst_expr) : Exit early if args
is empty.

gcc/testsuite/ChangeLog:

* g++.dg/template/non-dependent33.C: New test.
---
 gcc/cp/pt.cc|  2 +-
 gcc/testsuite/g++.dg/template/non-dependent33.C | 11 +++
 2 files changed, 12 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/template/non-dependent33.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 32640f8e946..e185e3d8941 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -21519,7 +21519,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
 
if (DECL_TEMPLATE_PARM_P (t))
  RETURN (RECUR (DECL_INITIAL (t)));
-   if (!uses_template_parms (DECL_CONTEXT (t)))
+   if (!args || !uses_template_parms (DECL_CONTEXT (t)))
  RETURN (t);
 
/* Unfortunately, we cannot just call lookup_name here.
diff --git a/gcc/testsuite/g++.dg/template/non-dependent33.C 
b/gcc/testsuite/g++.dg/template/non-dependent33.C
new file mode 100644
index 000..2f1dd8a214c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/non-dependent33.C
@@ -0,0 +1,11 @@
+// PR c++/115139
+// { dg-do compile { target c++11 } }
+
+template
+class A {
+  enum E {
+e1 = 1,
+e2 = 2,
+e3 = e1 | e2,
+  };
+};
-- 
2.45.1.204.gd8ab1d464d



[PATCH] c++: paren aggr CTAD with base classes [PR115114]

2024-05-16 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
OK for trunk and perhaps 14?

-- >8 --

We're accidentally ignoring base classes during parenthesized aggregate
CTAD because the TYPE_FIELDS of a template type doesn't contain bases,
so we need to consider them separately.

PR c++/115114

gcc/cp/ChangeLog:

* pt.cc (maybe_aggr_guide): Consider base classes in the paren
init case.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/class-deduction-aggr15.C: New test.
---
 gcc/cp/pt.cc  |  7 ++
 .../g++.dg/cpp2a/class-deduction-aggr15.C | 23 +++
 2 files changed, 30 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr15.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index d83f530ac8d..54d74989903 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -30202,6 +30202,13 @@ maybe_aggr_guide (tree tmpl, tree init, 
vec *args)
   else if (TREE_CODE (init) == TREE_LIST)
 {
   int len = list_length (init);
+  for (tree binfo : BINFO_BASE_BINFOS (TYPE_BINFO (template_type)))
+   {
+ if (!len)
+   break;
+ parms = tree_cons (NULL_TREE, BINFO_TYPE (binfo), parms);
+ --len;
+   }
   for (tree field = TYPE_FIELDS (template_type);
   len;
   --len, field = DECL_CHAIN (field))
diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr15.C 
b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr15.C
new file mode 100644
index 000..16dc0f52b64
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr15.C
@@ -0,0 +1,23 @@
+// PR c++/115114
+// { dg-do compile { target c++20 } }
+
+struct X {} x;
+struct Y {} y;
+
+template
+struct A : T {
+  U m;
+};
+
+using ty1 = decltype(A{x, 42}); // OK
+using ty1 = decltype(A(x, 42)); // OK, used to fail
+using ty1 = A;
+
+template
+struct B : T, V {
+  U m = 42;
+};
+
+using ty2 = decltype(B{x, y}); // OK
+using ty2 = decltype(B(x, y)); // OK, used to fail
+using ty2 = B;
-- 
2.45.1.190.g19fe900cfc



[PATCH] c++: represent all class non-dep assignments as CALL_EXPR

2024-05-15 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linu-xgnu, does this look OK
for trunk?

-- >8 --

Non-dependent compound assignment expressions are currently represented
as CALL_EXPR to the selected operator@= overload.  Non-dependent simple
assignments on the other hand are still represented as MODOP_EXPR, which
doesn't hold on to the selected overload.

That we need to remember the selected operator@= overload ahead of time
is a correctness thing, because they can be declared at namespace scope
and we don't want to consider later-declared namespace scope overloads
at instantiation time.  This doesn't apply to simple operator= because
it can only be declared at class scope, so it's fine to repeat the name
lookup and overload resolution at instantiation time.  But it still
seems desirable for sake of QoI to also avoid this repeated name lookup
and overload resolution for simple assignments along the lines of
r12-6075-g2decd2cabe5a4f.

To that end, this patch makes us represent non-dependent simple
assignments as CALL_EXPR to the selected operator= overload rather than
as MODOP_EXPR.  In order for is_assignment_op_expr_p to recognize such
CALL_EXPR as an assignment expression, cp_get_fndecl_from_callee needs
to look through templated COMPONENT_REF callee corresponding to a member
function call, otherwise ahead of time -Wparentheses warnings stop
working (e.g. g++.dg/warn/Wparentheses-{32,33}.C).

gcc/cp/ChangeLog:

* call.cc (build_new_op): Pass 'overload' to
cp_build_modify_expr.
* cp-tree.h (cp_build_modify_expr): New overload that
takes a tree* out-parameter.
* pt.cc (tsubst_expr) : Propagate
OPT_Wparentheses warning suppression to the result.
* cvt.cc (cp_get_fndecl_from_callee): Use maybe_get_fns
to extract the FUNCTION_DECL from a callee.
* semantics.cc (is_assignment_op_expr_p): Also recognize
templated operator expressions represented as a CALL_EXPR
to operator=.
* typeck.cc (cp_build_modify_expr): Add 'overload'
out-parameter and pass it to build_new_op.
(build_x_modify_expr): Pass 'overload' to cp_build_modify_expr.
---
 gcc/cp/call.cc   |  2 +-
 gcc/cp/cp-tree.h |  3 +++
 gcc/cp/cvt.cc|  5 +++--
 gcc/cp/pt.cc |  2 ++
 gcc/cp/typeck.cc | 18 ++
 5 files changed, 23 insertions(+), 7 deletions(-)

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index e058da7735f..e3d4cf8949d 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -7473,7 +7473,7 @@ build_new_op (const op_location_t , enum tree_code 
code, int flags,
   switch (code)
 {
 case MODIFY_EXPR:
-  return cp_build_modify_expr (loc, arg1, code2, arg2, complain);
+  return cp_build_modify_expr (loc, arg1, code2, arg2, overload, complain);
 
 case INDIRECT_REF:
   return cp_build_indirect_ref (loc, arg1, RO_UNARY_STAR, complain);
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 9a8c8659157..1e565086e80 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -8267,6 +8267,9 @@ extern tree cp_build_c_cast   
(location_t, tree, tree,
 extern cp_expr build_x_modify_expr (location_t, tree,
 enum tree_code, tree,
 tree, tsubst_flags_t);
+extern tree cp_build_modify_expr   (location_t, tree,
+enum tree_code, tree,
+tree *, tsubst_flags_t);
 extern tree cp_build_modify_expr   (location_t, tree,
 enum tree_code, tree,
 tsubst_flags_t);
diff --git a/gcc/cp/cvt.cc b/gcc/cp/cvt.cc
index db086c017e8..2f4c0f88694 100644
--- a/gcc/cp/cvt.cc
+++ b/gcc/cp/cvt.cc
@@ -1015,8 +1015,9 @@ cp_get_fndecl_from_callee (tree fn, bool fold /* = true 
*/)
   return f;
 };
 
-  if (TREE_CODE (fn) == FUNCTION_DECL)
-return fn_or_local_alias (fn);
+  if (tree f = maybe_get_fns (fn))
+if (TREE_CODE (f) == FUNCTION_DECL)
+  return fn_or_local_alias (f);
   tree type = TREE_TYPE (fn);
   if (type == NULL_TREE || !INDIRECT_TYPE_P (type))
 return NULL_TREE;
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 32640f8e946..d83f530ac8d 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -21093,6 +21093,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
if (warning_suppressed_p (t, OPT_Wpessimizing_move))
  /* This also suppresses -Wredundant-move.  */
  suppress_warning (ret, OPT_Wpessimizing_move);
+   if (warning_suppressed_p (t, OPT_Wparentheses))
+ suppress_warning (STRIP_REFERENCE_REF (ret), OPT_Wparentheses);
  }
 
RETURN (ret);
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 5f16994300f..75b696e32e0 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -9421,7 +9421,7 

Re: [PATCH v3] c++: Fix auto deduction for template specialization scopes [PR114915]

2024-05-15 Thread Patrick Palka
On Wed, 15 May 2024, Patrick Palka wrote:

> 
> On Fri, 10 May 2024, Seyed Sajad Kahani wrote:
> 
> > This patch resolves PR114915 by replacing the logic that fills in the 
> > missing levels in do_auto_deduction in cp/pt.cc.
> > The new approach now trims targs if the depth of targs is deeper than 
> > desired (this will only happen in specific contexts), and still fills targs 
> > with empty layers if it has fewer depths than expected.
> 
> The logic looks good to me, thanks!  Note that as per
> https://gcc.gnu.org/contribute.html patches need a ChangeLog entry in
> the commit message, for example let's use:
> 
>   PR c++/114915
> 
> gcc/cp/ChangeLog:
> 
>   * pt.cc (do_auto_deduction): Handle excess outer template
>   arguments during constrained auto satisfaction.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp2a/concepts-placeholder14.C: New test.
>   * g++.dg/cpp2a/concepts-placeholder15.C: New test.
>   * g++.dg/cpp2a/concepts-placeholder16.C: New test.
> 
> Jason, what do you think?

... now sent to the correct email, sorry for the spam

> 
> > ---
> >  gcc/cp/pt.cc  | 20 ---
> >  .../g++.dg/cpp2a/concepts-placeholder14.C | 19 +++
> >  .../g++.dg/cpp2a/concepts-placeholder15.C | 15 +
> >  .../g++.dg/cpp2a/concepts-placeholder16.C | 33 +++
> >  4 files changed, 83 insertions(+), 4 deletions(-)
> >  create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
> >  create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
> >  create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
> > 
> > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > index 3b2106dd3..479b2a5bd 100644
> > --- a/gcc/cp/pt.cc
> > +++ b/gcc/cp/pt.cc
> > @@ -31253,6 +31253,19 @@ do_auto_deduction (tree type, tree init, tree 
> > auto_node,
> > full_targs = add_outermost_template_args (tmpl, full_targs);
> >full_targs = add_to_template_args (full_targs, targs);
> >  
> > +  int want = TEMPLATE_TYPE_ORIG_LEVEL (auto_node);
> > +  int have = TMPL_ARGS_DEPTH (full_targs);
> > +
> > +  if (want < have)
> > +   {
> > + // if a constrained auto is declared in an explicit specialization
> > + gcc_assert (context == adc_variable_type || context == adc_return_type
> > + || context == adc_decomp_type);
> > + tree trimmed_full_args = get_innermost_template_args
> > +   (full_targs, want);
> > + full_targs = trimmed_full_args;
> > +   }
> > +  
> >/* HACK: Compensate for callers not always communicating all levels 
> > of
> >  outer template arguments by filling in the outermost missing levels
> >  with dummy levels before checking satisfaction.  We'll still crash
> > @@ -31260,11 +31273,10 @@ do_auto_deduction (tree type, tree init, tree 
> > auto_node,
> >  these missing levels, but this hack otherwise allows us to handle a
> >  large subset of possible constraints (including all non-dependent
> >  constraints).  */
> > -  if (int missing_levels = (TEMPLATE_TYPE_ORIG_LEVEL (auto_node)
> > -   - TMPL_ARGS_DEPTH (full_targs)))
> > +  if (want > have)
> > {
> > - tree dummy_levels = make_tree_vec (missing_levels);
> > - for (int i = 0; i < missing_levels; ++i)
> > + tree dummy_levels = make_tree_vec (want - have);
> > + for (int i = 0; i < want - have; ++i)
> > TREE_VEC_ELT (dummy_levels, i) = make_tree_vec (0);
> >   full_targs = add_to_template_args (dummy_levels, full_targs);
> > }
> > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C 
> > b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
> > new file mode 100644
> > index 0..fcdbd7608
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
> > @@ -0,0 +1,19 @@
> > +// PR c++/114915
> > +// { dg-do compile { target c++20 } }
> > +
> > +template
> > +concept C = __is_same(T, int);
> > +
> > +template
> > +void f() {
> > +}
> > +
> > +template<>
> > +void f() {
> > +  C auto x = 1;
> > +}
> > +
> > +int main() {
> > +  f();
> > +  return 0;
> > +}
> > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C 
> > b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
> > new file mode 100644
> > index 0..b4f73f407
> > --- /dev/

Re: [PATCH v3] c++: Fix auto deduction for template specialization scopes [PR114915]

2024-05-15 Thread Patrick Palka


On Fri, 10 May 2024, Seyed Sajad Kahani wrote:

> This patch resolves PR114915 by replacing the logic that fills in the missing 
> levels in do_auto_deduction in cp/pt.cc.
> The new approach now trims targs if the depth of targs is deeper than desired 
> (this will only happen in specific contexts), and still fills targs with 
> empty layers if it has fewer depths than expected.

The logic looks good to me, thanks!  Note that as per
https://gcc.gnu.org/contribute.html patches need a ChangeLog entry in
the commit message, for example let's use:

PR c++/114915

gcc/cp/ChangeLog:

* pt.cc (do_auto_deduction): Handle excess outer template
arguments during constrained auto satisfaction.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts-placeholder14.C: New test.
* g++.dg/cpp2a/concepts-placeholder15.C: New test.
* g++.dg/cpp2a/concepts-placeholder16.C: New test.

Jason, what do you think?

> ---
>  gcc/cp/pt.cc  | 20 ---
>  .../g++.dg/cpp2a/concepts-placeholder14.C | 19 +++
>  .../g++.dg/cpp2a/concepts-placeholder15.C | 15 +
>  .../g++.dg/cpp2a/concepts-placeholder16.C | 33 +++
>  4 files changed, 83 insertions(+), 4 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
> 
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 3b2106dd3..479b2a5bd 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -31253,6 +31253,19 @@ do_auto_deduction (tree type, tree init, tree 
> auto_node,
>   full_targs = add_outermost_template_args (tmpl, full_targs);
>full_targs = add_to_template_args (full_targs, targs);
>  
> +  int want = TEMPLATE_TYPE_ORIG_LEVEL (auto_node);
> +  int have = TMPL_ARGS_DEPTH (full_targs);
> +
> +  if (want < have)
> + {
> +   // if a constrained auto is declared in an explicit specialization
> +   gcc_assert (context == adc_variable_type || context == adc_return_type
> +   || context == adc_decomp_type);
> +   tree trimmed_full_args = get_innermost_template_args
> + (full_targs, want);
> +   full_targs = trimmed_full_args;
> + }
> +  
>/* HACK: Compensate for callers not always communicating all levels of
>outer template arguments by filling in the outermost missing levels
>with dummy levels before checking satisfaction.  We'll still crash
> @@ -31260,11 +31273,10 @@ do_auto_deduction (tree type, tree init, tree 
> auto_node,
>these missing levels, but this hack otherwise allows us to handle a
>large subset of possible constraints (including all non-dependent
>constraints).  */
> -  if (int missing_levels = (TEMPLATE_TYPE_ORIG_LEVEL (auto_node)
> - - TMPL_ARGS_DEPTH (full_targs)))
> +  if (want > have)
>   {
> -   tree dummy_levels = make_tree_vec (missing_levels);
> -   for (int i = 0; i < missing_levels; ++i)
> +   tree dummy_levels = make_tree_vec (want - have);
> +   for (int i = 0; i < want - have; ++i)
>   TREE_VEC_ELT (dummy_levels, i) = make_tree_vec (0);
> full_targs = add_to_template_args (dummy_levels, full_targs);
>   }
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C 
> b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
> new file mode 100644
> index 0..fcdbd7608
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
> @@ -0,0 +1,19 @@
> +// PR c++/114915
> +// { dg-do compile { target c++20 } }
> +
> +template
> +concept C = __is_same(T, int);
> +
> +template
> +void f() {
> +}
> +
> +template<>
> +void f() {
> +  C auto x = 1;
> +}
> +
> +int main() {
> +  f();
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C 
> b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
> new file mode 100644
> index 0..b4f73f407
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
> @@ -0,0 +1,15 @@
> +// PR c++/114915
> +// { dg-do compile { target c++20 } }
> +
> +template
> +concept C = __is_same(T, U);
> +
> +template
> +int x = 0;
> +
> +template<>
> +C auto x = 1.0;
> +
> +int main() {
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C 
> b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
> new file mode 100644
> index 0..f808ef1b6
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
> @@ -0,0 +1,33 @@
> +// PR c++/114915
> +// { dg-do compile { target c++20 } }
> +
> +template
> +concept C = __is_same(T, U);
> +
> +template
> +struct A
> +{ 
> +template
> +void f() {
> +}
> +};
> + 
> +template<>
> +template<>
> +void A::f() {
> +  C auto x = 1;
> +}
> +
> +template<>
> +template
> +void 

Re: [PATCH] c++: lvalueness of non-dependent assignment [PR114994]

2024-05-11 Thread Patrick Palka
On Fri, 10 May 2024, Jason Merrill wrote:

> On 5/9/24 16:23, Patrick Palka wrote:
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> > OK for trunk/14?  For trunk as a follow-up I can implement the
> > mentionted representation change to use CALL_EXPR instead of
> > MODOP_EXPR for a non-dependent simple assignment expression that
> > resolved to an operator= overload.
> > 
> > -- >8 --
> > 
> > r14-4111 made us check non-dependent assignment expressions ahead of
> > time, as well as give them a type.  Unlike for compound assignment
> > expressions however, if a simple assignment resolves to an operator
> > overload we still represent it as a (typed) MODOP_EXPR instead of a
> > CALL_EXPR to the selected overload.  This, I reckoned, was just a
> > pessimization (since we'll have to repeat overload resolution at
> > instantiatiation time) but should be harmless.  (And it should be
> > easily fixable by giving cp_build_modify_expr an 'overload' parameter).
> > 
> > But it breaks the below testcase ultimately because MODOP_EXPR (of
> > non-reference type) is always treated as an lvalue according to
> > lvalue_kind, which is incorrect for the MODOP_EXPR representing x=42.
> > 
> > We can fix this by representing such assignment expressions as CALL_EXPRs
> > matching what that of compound assignments, but that turns out to
> > require some tweaking of our -Wparentheses warning logic which seems
> > unsuitable for backporting.
> > 
> > So this patch instead more conservatively fixes this by refining
> > lvalue_kind to consider the type of a (simple) MODOP_EXPR as we
> > already do for COND_EXPR.
> > 
> > PR c++/114994
> > 
> > gcc/cp/ChangeLog:
> > 
> > * tree.cc (lvalue_kind) : Consider the
> > type of a simple assignment expression.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/template/non-dependent32.C: New test.
> > ---
> >   gcc/cp/tree.cc |  7 +++
> >   .../g++.dg/template/non-dependent32.C  | 18 ++
> >   2 files changed, 25 insertions(+)
> >   create mode 100644 gcc/testsuite/g++.dg/template/non-dependent32.C
> > 
> > diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
> > index f1a23ffe817..0b97b789aab 100644
> > --- a/gcc/cp/tree.cc
> > +++ b/gcc/cp/tree.cc
> > @@ -275,6 +275,13 @@ lvalue_kind (const_tree ref)
> > /* We expect to see unlowered MODOP_EXPRs only during
> >  template processing.  */
> > gcc_assert (processing_template_decl);
> > +  if (TREE_CODE (TREE_OPERAND (ref, 1)) == NOP_EXPR
> > + && CLASS_TYPE_P (TREE_TYPE (TREE_OPERAND (ref, 0
> > +   /* As in the COND_EXPR case, but for non-dependent assignment
> > +  expressions created by build_x_modify_expr.  */
> > +   goto default_;
> 
> This seems overly specific, I'd think the same thing would apply to += and
> such?

We shouldn't see += etc of class type here since we already represent
those as CALL_EXPR to the selected operator=, but indeed it could
otherwise apply to +=.  Like so?

-- >8 -- 

Subject: [PATCH] c++: lvalueness of non-dependent assignment expr [PR114994]

PR c++/114994

gcc/cp/ChangeLog:

* tree.cc (lvalue_kind) : Consider the
type of a class assignment expression.

gcc/testsuite/ChangeLog:

* g++.dg/template/non-dependent32.C: New test.
---
 gcc/cp/tree.cc |  5 -
 .../g++.dg/template/non-dependent32.C  | 18 ++
 2 files changed, 22 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/template/non-dependent32.C

diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index f1a23ffe817..9d37d255d8d 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -275,7 +275,10 @@ lvalue_kind (const_tree ref)
   /* We expect to see unlowered MODOP_EXPRs only during
 template processing.  */
   gcc_assert (processing_template_decl);
-  return clk_ordinary;
+  if (CLASS_TYPE_P (TREE_TYPE (TREE_OPERAND (ref, 0
+   goto default_;
+  else
+   return clk_ordinary;
 
 case MODIFY_EXPR:
 case TYPEID_EXPR:
diff --git a/gcc/testsuite/g++.dg/template/non-dependent32.C 
b/gcc/testsuite/g++.dg/template/non-dependent32.C
new file mode 100644
index 000..54252c7dfaf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/non-dependent32.C
@@ -0,0 +1,18 @@
+// PR c++/114994
+// { dg-do compile { target c++11 } }
+
+struct udl_arg {
+  udl_arg operator=(int);
+};
+
+void f(udl_arg&&);
+
+template
+void g() {
+  udl_arg x;
+  f(x=42); // { dg-bogus "cannot bind" }
+}
+
+int mai

Re: [PATCH] c++: lvalueness of non-dependent assignment [PR114994]

2024-05-10 Thread Patrick Palka
On Thu, 9 May 2024, Patrick Palka wrote:

> On Thu, 9 May 2024, Patrick Palka wrote:
> 
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> > OK for trunk/14?  For trunk as a follow-up I can implement the
> > mentionted representation change to use CALL_EXPR instead of
> > MODOP_EXPR for a non-dependent simple assignment expression that
> > resolved to an operator= overload.
> 
> FWIW, this is the WIP patch for that including the -Wparentheses
> logic adjustments needed to avoid regressing
> g++.dg/warn/Wparentheses-{32,33}.C

This patch survives bootstrap+regtest FWIW.  I'm not sure which approach
we should go with for backporting.

> 
>   PR c++/114994
> 
> gcc/cp/ChangeLog:
> 
>   * call.cc (build_new_op): Pass 'overload' to
>   cp_build_modify_expr.
>   * cp-tree.h (cp_build_modify_expr): New overload that
>   takes a tree* out-parameter.
>   * pt.cc (tsubst_expr) : Propagate
>   OPT_Wparentheses warning suppression to the result.
>   * semantics.cc (is_assignment_op_expr_p): Also recognize
>   templated operator expressions represented as a CALL_EXPR
>   to operator=.
>   * typeck.cc (cp_build_modify_expr): Add 'overload'
>   out-parameter and pass it to build_new_op.
>   (build_x_modify_expr): Pass 'overload' to cp_build_modify_expr.
> ---
>  gcc/cp/call.cc |  2 +-
>  gcc/cp/cp-tree.h   |  3 +++
>  gcc/cp/pt.cc   |  2 ++
>  gcc/cp/semantics.cc| 11 +++
>  gcc/cp/typeck.cc   | 18 ++
>  5 files changed, 31 insertions(+), 5 deletions(-)
> 
> diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
> index 7c4ecf08c4b..1cd4992330c 100644
> --- a/gcc/cp/call.cc
> +++ b/gcc/cp/call.cc
> @@ -7473,7 +7473,7 @@ build_new_op (const op_location_t , enum tree_code 
> code, int flags,
>switch (code)
>  {
>  case MODIFY_EXPR:
> -  return cp_build_modify_expr (loc, arg1, code2, arg2, complain);
> +  return cp_build_modify_expr (loc, arg1, code2, arg2, overload, 
> complain);
>  
>  case INDIRECT_REF:
>return cp_build_indirect_ref (loc, arg1, RO_UNARY_STAR, complain);
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index f82446331b3..505c04c6e52 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -8264,6 +8264,9 @@ extern tree cp_build_c_cast 
> (location_t, tree, tree,
>  extern cp_expr build_x_modify_expr   (location_t, tree,
>enum tree_code, tree,
>tree, tsubst_flags_t);
> +extern tree cp_build_modify_expr (location_t, tree,
> +  enum tree_code, tree,
> +  tree *, tsubst_flags_t);
>  extern tree cp_build_modify_expr (location_t, tree,
>enum tree_code, tree,
>tsubst_flags_t);
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index f3d52acaaac..bc71e534cf8 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -21091,6 +21091,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
> complain, tree in_decl)
>   if (warning_suppressed_p (t, OPT_Wpessimizing_move))
> /* This also suppresses -Wredundant-move.  */
> suppress_warning (ret, OPT_Wpessimizing_move);
> + if (warning_suppressed_p (t, OPT_Wparentheses))
> +   suppress_warning (STRIP_REFERENCE_REF (ret), OPT_Wparentheses);
> }
>  
>   RETURN (ret);
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index b8c2bf8771f..e81f2b50d80 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -863,6 +863,17 @@ is_assignment_op_expr_p (tree t)
>  return false;
>  
>tree fndecl = cp_get_callee_fndecl_nofold (call);
> +  if (!fndecl
> +  && processing_template_decl
> +  && TREE_CODE (CALL_EXPR_FN (call)) == COMPONENT_REF)
> +{
> +  /* Also recognize (non-dependent) templated operator expressions that
> +  are represented as a direct call to operator=.
> +  TODO: maybe move this handling to cp_get_fndecl_from_callee for
> +  benefit of other callers.  */
> +  if (tree fns = maybe_get_fns (TREE_OPERAND (CALL_EXPR_FN (call), 1)))
> + fndecl = OVL_FIRST (fns);
> +}
>return fndecl != NULL_TREE
>  && DECL_ASSIGNMENT_OPERATOR_P (fndecl)
>  && DECL_OVERLOADED_OPERATOR_IS (fndecl, NOP_EXPR

Re: [PATCH] c++: lvalueness of non-dependent assignment [PR114994]

2024-05-09 Thread Patrick Palka
On Thu, 9 May 2024, Patrick Palka wrote:

> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> OK for trunk/14?  For trunk as a follow-up I can implement the
> mentionted representation change to use CALL_EXPR instead of
> MODOP_EXPR for a non-dependent simple assignment expression that
> resolved to an operator= overload.

FWIW, this is the WIP patch for that including the -Wparentheses
logic adjustments needed to avoid regressing
g++.dg/warn/Wparentheses-{32,33}.C

PR c++/114994

gcc/cp/ChangeLog:

* call.cc (build_new_op): Pass 'overload' to
cp_build_modify_expr.
* cp-tree.h (cp_build_modify_expr): New overload that
takes a tree* out-parameter.
* pt.cc (tsubst_expr) : Propagate
OPT_Wparentheses warning suppression to the result.
* semantics.cc (is_assignment_op_expr_p): Also recognize
templated operator expressions represented as a CALL_EXPR
to operator=.
* typeck.cc (cp_build_modify_expr): Add 'overload'
out-parameter and pass it to build_new_op.
(build_x_modify_expr): Pass 'overload' to cp_build_modify_expr.
---
 gcc/cp/call.cc |  2 +-
 gcc/cp/cp-tree.h   |  3 +++
 gcc/cp/pt.cc   |  2 ++
 gcc/cp/semantics.cc| 11 +++
 gcc/cp/typeck.cc   | 18 ++
 5 files changed, 31 insertions(+), 5 deletions(-)

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 7c4ecf08c4b..1cd4992330c 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -7473,7 +7473,7 @@ build_new_op (const op_location_t , enum tree_code 
code, int flags,
   switch (code)
 {
 case MODIFY_EXPR:
-  return cp_build_modify_expr (loc, arg1, code2, arg2, complain);
+  return cp_build_modify_expr (loc, arg1, code2, arg2, overload, complain);
 
 case INDIRECT_REF:
   return cp_build_indirect_ref (loc, arg1, RO_UNARY_STAR, complain);
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index f82446331b3..505c04c6e52 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -8264,6 +8264,9 @@ extern tree cp_build_c_cast   
(location_t, tree, tree,
 extern cp_expr build_x_modify_expr (location_t, tree,
 enum tree_code, tree,
 tree, tsubst_flags_t);
+extern tree cp_build_modify_expr   (location_t, tree,
+enum tree_code, tree,
+tree *, tsubst_flags_t);
 extern tree cp_build_modify_expr   (location_t, tree,
 enum tree_code, tree,
 tsubst_flags_t);
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index f3d52acaaac..bc71e534cf8 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -21091,6 +21091,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
if (warning_suppressed_p (t, OPT_Wpessimizing_move))
  /* This also suppresses -Wredundant-move.  */
  suppress_warning (ret, OPT_Wpessimizing_move);
+   if (warning_suppressed_p (t, OPT_Wparentheses))
+ suppress_warning (STRIP_REFERENCE_REF (ret), OPT_Wparentheses);
  }
 
RETURN (ret);
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index b8c2bf8771f..e81f2b50d80 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -863,6 +863,17 @@ is_assignment_op_expr_p (tree t)
 return false;
 
   tree fndecl = cp_get_callee_fndecl_nofold (call);
+  if (!fndecl
+  && processing_template_decl
+  && TREE_CODE (CALL_EXPR_FN (call)) == COMPONENT_REF)
+{
+  /* Also recognize (non-dependent) templated operator expressions that
+are represented as a direct call to operator=.
+TODO: maybe move this handling to cp_get_fndecl_from_callee for
+benefit of other callers.  */
+  if (tree fns = maybe_get_fns (TREE_OPERAND (CALL_EXPR_FN (call), 1)))
+   fndecl = OVL_FIRST (fns);
+}
   return fndecl != NULL_TREE
 && DECL_ASSIGNMENT_OPERATOR_P (fndecl)
 && DECL_OVERLOADED_OPERATOR_IS (fndecl, NOP_EXPR);
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 5f16994300f..75b696e32e0 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -9421,7 +9421,7 @@ build_modify_expr (location_t location,
 
 tree
 cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
- tree rhs, tsubst_flags_t complain)
+ tree rhs, tree *overload, tsubst_flags_t complain)
 {
   lhs = mark_lvalue_use_nonread (lhs);
 
@@ -9533,7 +9533,8 @@ cp_build_modify_expr (location_t loc, tree lhs, enum 
tree_code modifycode,
  rhs = unshare_expr (rhs);
tree op2 = TR

[PATCH] c++: lvalueness of non-dependent assignment [PR114994]

2024-05-09 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
OK for trunk/14?  For trunk as a follow-up I can implement the
mentionted representation change to use CALL_EXPR instead of
MODOP_EXPR for a non-dependent simple assignment expression that
resolved to an operator= overload.

-- >8 --

r14-4111 made us check non-dependent assignment expressions ahead of
time, as well as give them a type.  Unlike for compound assignment
expressions however, if a simple assignment resolves to an operator
overload we still represent it as a (typed) MODOP_EXPR instead of a
CALL_EXPR to the selected overload.  This, I reckoned, was just a
pessimization (since we'll have to repeat overload resolution at
instantiatiation time) but should be harmless.  (And it should be
easily fixable by giving cp_build_modify_expr an 'overload' parameter).

But it breaks the below testcase ultimately because MODOP_EXPR (of
non-reference type) is always treated as an lvalue according to
lvalue_kind, which is incorrect for the MODOP_EXPR representing x=42.

We can fix this by representing such assignment expressions as CALL_EXPRs
matching what that of compound assignments, but that turns out to
require some tweaking of our -Wparentheses warning logic which seems
unsuitable for backporting.

So this patch instead more conservatively fixes this by refining
lvalue_kind to consider the type of a (simple) MODOP_EXPR as we
already do for COND_EXPR.

PR c++/114994

gcc/cp/ChangeLog:

* tree.cc (lvalue_kind) : Consider the
type of a simple assignment expression.

gcc/testsuite/ChangeLog:

* g++.dg/template/non-dependent32.C: New test.
---
 gcc/cp/tree.cc |  7 +++
 .../g++.dg/template/non-dependent32.C  | 18 ++
 2 files changed, 25 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/template/non-dependent32.C

diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index f1a23ffe817..0b97b789aab 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -275,6 +275,13 @@ lvalue_kind (const_tree ref)
   /* We expect to see unlowered MODOP_EXPRs only during
 template processing.  */
   gcc_assert (processing_template_decl);
+  if (TREE_CODE (TREE_OPERAND (ref, 1)) == NOP_EXPR
+ && CLASS_TYPE_P (TREE_TYPE (TREE_OPERAND (ref, 0
+   /* As in the COND_EXPR case, but for non-dependent assignment
+  expressions created by build_x_modify_expr.  */
+   goto default_;
+  /* A non-dependent (simple or compound) assignment expression that
+resolved to a built-in assignment function.  */
   return clk_ordinary;
 
 case MODIFY_EXPR:
diff --git a/gcc/testsuite/g++.dg/template/non-dependent32.C 
b/gcc/testsuite/g++.dg/template/non-dependent32.C
new file mode 100644
index 000..54252c7dfaf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/non-dependent32.C
@@ -0,0 +1,18 @@
+// PR c++/114994
+// { dg-do compile { target c++11 } }
+
+struct udl_arg {
+  udl_arg operator=(int);
+};
+
+void f(udl_arg&&);
+
+template
+void g() {
+  udl_arg x;
+  f(x=42); // { dg-bogus "cannot bind" }
+}
+
+int main() {
+  g();
+}
-- 
2.45.0.119.g0f3415f1f8



Re: [PATCH] c++: nested aggregate/alias CTAD fixes

2024-05-08 Thread Patrick Palka
On Wed, 8 May 2024, Patrick Palka wrote:

> Bootstrapped and regtested on x86-64-pc-linux-gnu, does this look
> OK for trunk and perhaps 14?
> 
> -- >8 --
> 
> During maybe_aggr_guide with a nested class template and paren init,
> like with list init we need to consider the generic template type rather
> than the partially instantiated type since only the former has
> TYPE_FIELDS.  And in turn we need to partially substitute PARMs in the
> paren init case as well.  As a drive-by improvement it seems better to
> use outer_template_args instead of DECL_TI_ARGS during this partial
> substitution so that we lower instead of substitute the innermost
> generic template arguments, which is generally more robust.

... lower instead of substitute the innermost _template parameters_, rather

> 
> And during alias_ctad_tweaks with a nested class template, even though
> the guides may be already partially instantiated we still need to
> use the full set of arguments, not just the innermost, when substituting
> its constraints.
> 
>   PR c++/114974
>   PR c++/114901
>   PR c++/114903
> 
> gcc/cp/ChangeLog:
> 
>   * pt.cc (maybe_aggr_guide): Fix obtaining TYPE_FIELDS in
>   the paren init case.  Hoist out partial substitution logic
>   to apply to the paren init case as well.
>   (alias_ctad_tweaks): Substitute constraints using the full
>   set of template arguments.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp2a/class-deduction-aggr14.C: New test.
>   * g++.dg/cpp2a/class-deduction-alias20.C: New test.
>   * g++.dg/cpp2a/class-deduction-alias21.C: New test.
> ---
>  gcc/cp/pt.cc  | 39 +++
>  .../g++.dg/cpp2a/class-deduction-aggr14.C | 11 ++
>  .../g++.dg/cpp2a/class-deduction-alias20.C| 22 +++
>  .../g++.dg/cpp2a/class-deduction-alias21.C| 38 ++
>  4 files changed, 93 insertions(+), 17 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr14.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-alias20.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-alias21.C
> 
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 1816bfd1f40..f3d52acaaac 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -30192,26 +30192,11 @@ maybe_aggr_guide (tree tmpl, tree init, 
> vec *args)
>if (init == error_mark_node)
>   return NULL_TREE;
>parms = collect_ctor_idx_types (init, parms);
> -  /* If we're creating a deduction guide for a member class template,
> -  we've used the original template pattern type for the reshape_init
> -  above; this is done because we want PARMS to be a template parameter
> -  type, something that can be deduced when used as a function template
> -  parameter.  At this point the outer class template has already been
> -  partially instantiated (we deferred the deduction until the enclosing
> -  scope is non-dependent).  Therefore we have to partially instantiate
> -  PARMS, so that its template level is properly reduced and we don't get
> -  mismatches when deducing types using the guide with PARMS.  */
> -  if (member_template_p)
> - {
> -   ++processing_template_decl;
> -   parms = tsubst (parms, DECL_TI_ARGS (tmpl), complain, init);
> -   --processing_template_decl;
> - }
>  }
>else if (TREE_CODE (init) == TREE_LIST)
>  {
>int len = list_length (init);
> -  for (tree field = TYPE_FIELDS (type);
> +  for (tree field = TYPE_FIELDS (template_type);
>  len;
>  --len, field = DECL_CHAIN (field))
>   {
> @@ -30226,6 +30211,22 @@ maybe_aggr_guide (tree tmpl, tree init, 
> vec *args)
>  /* Aggregate initialization doesn't apply to an initializer expression.  
> */
>  return NULL_TREE;
>  
> +  /* If we're creating a deduction guide for a member class template,
> + we've used the original template pattern type for the reshape_init
> + above; this is done because we want PARMS to be a template parameter
> + type, something that can be deduced when used as a function template
> + parameter.  At this point the outer class template has already been
> + partially instantiated (we deferred the deduction until the enclosing
> + scope is non-dependent).  Therefore we have to partially instantiate
> + PARMS, so that its template level is properly reduced and we don't get
> + mismatches when deducing types using the guide with PARMS.  */
> +  if (member_template_p)
> +{
> +  ++processing_template_decl;
> +  parms = tsubst (parms, outer_template_args (tmpl), complai

[PATCH] c++: nested aggregate/alias CTAD fixes

2024-05-08 Thread Patrick Palka
Bootstrapped and regtested on x86-64-pc-linux-gnu, does this look
OK for trunk and perhaps 14?

-- >8 --

During maybe_aggr_guide with a nested class template and paren init,
like with list init we need to consider the generic template type rather
than the partially instantiated type since only the former has
TYPE_FIELDS.  And in turn we need to partially substitute PARMs in the
paren init case as well.  As a drive-by improvement it seems better to
use outer_template_args instead of DECL_TI_ARGS during this partial
substitution so that we lower instead of substitute the innermost
generic template arguments, which is generally more robust.

And during alias_ctad_tweaks with a nested class template, even though
the guides may be already partially instantiated we still need to
use the full set of arguments, not just the innermost, when substituting
its constraints.

PR c++/114974
PR c++/114901
PR c++/114903

gcc/cp/ChangeLog:

* pt.cc (maybe_aggr_guide): Fix obtaining TYPE_FIELDS in
the paren init case.  Hoist out partial substitution logic
to apply to the paren init case as well.
(alias_ctad_tweaks): Substitute constraints using the full
set of template arguments.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/class-deduction-aggr14.C: New test.
* g++.dg/cpp2a/class-deduction-alias20.C: New test.
* g++.dg/cpp2a/class-deduction-alias21.C: New test.
---
 gcc/cp/pt.cc  | 39 +++
 .../g++.dg/cpp2a/class-deduction-aggr14.C | 11 ++
 .../g++.dg/cpp2a/class-deduction-alias20.C| 22 +++
 .../g++.dg/cpp2a/class-deduction-alias21.C| 38 ++
 4 files changed, 93 insertions(+), 17 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr14.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-alias20.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-alias21.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 1816bfd1f40..f3d52acaaac 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -30192,26 +30192,11 @@ maybe_aggr_guide (tree tmpl, tree init, 
vec *args)
   if (init == error_mark_node)
return NULL_TREE;
   parms = collect_ctor_idx_types (init, parms);
-  /* If we're creating a deduction guide for a member class template,
-we've used the original template pattern type for the reshape_init
-above; this is done because we want PARMS to be a template parameter
-type, something that can be deduced when used as a function template
-parameter.  At this point the outer class template has already been
-partially instantiated (we deferred the deduction until the enclosing
-scope is non-dependent).  Therefore we have to partially instantiate
-PARMS, so that its template level is properly reduced and we don't get
-mismatches when deducing types using the guide with PARMS.  */
-  if (member_template_p)
-   {
- ++processing_template_decl;
- parms = tsubst (parms, DECL_TI_ARGS (tmpl), complain, init);
- --processing_template_decl;
-   }
 }
   else if (TREE_CODE (init) == TREE_LIST)
 {
   int len = list_length (init);
-  for (tree field = TYPE_FIELDS (type);
+  for (tree field = TYPE_FIELDS (template_type);
   len;
   --len, field = DECL_CHAIN (field))
{
@@ -30226,6 +30211,22 @@ maybe_aggr_guide (tree tmpl, tree init, 
vec *args)
 /* Aggregate initialization doesn't apply to an initializer expression.  */
 return NULL_TREE;
 
+  /* If we're creating a deduction guide for a member class template,
+ we've used the original template pattern type for the reshape_init
+ above; this is done because we want PARMS to be a template parameter
+ type, something that can be deduced when used as a function template
+ parameter.  At this point the outer class template has already been
+ partially instantiated (we deferred the deduction until the enclosing
+ scope is non-dependent).  Therefore we have to partially instantiate
+ PARMS, so that its template level is properly reduced and we don't get
+ mismatches when deducing types using the guide with PARMS.  */
+  if (member_template_p)
+{
+  ++processing_template_decl;
+  parms = tsubst (parms, outer_template_args (tmpl), complain, init);
+  --processing_template_decl;
+}
+
   if (parms)
 {
   tree last = parms;
@@ -30417,7 +30418,11 @@ alias_ctad_tweaks (tree tmpl, tree uguides)
  /* Substitute the associated constraints.  */
  tree ci = get_constraints (f);
  if (ci)
-   ci = tsubst_constraint_info (ci, targs, complain, in_decl);
+   {
+ if (tree outer_targs = outer_template_args (f))
+   ci = tsubst_constraint_info (ci, outer_targs, complain, 
in_decl);
+ ci = tsubst_constraint_info 

Re: [PATCH v3] c++/modules: Fix dangling pointer with imported_temploid_friends

2024-05-06 Thread Patrick Palka
On Mon, 6 May 2024, Jason Merrill wrote:

> On 5/3/24 07:17, Nathaniel Shead wrote:
> > On Thu, May 02, 2024 at 02:05:38PM -0400, Jason Merrill wrote:
> > > On 5/1/24 21:34, Nathaniel Shead wrote:
> > > > On Thu, May 02, 2024 at 12:15:44AM +1000, Nathaniel Shead wrote:
> > > > > On Wed, May 01, 2024 at 09:57:38AM -0400, Patrick Palka wrote:
> > > > > > 
> > > > > > On Wed, 1 May 2024, Nathaniel Shead wrote:
> > > > > > 
> > > > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk
> > > > > > > (and
> > > > > > > later 14.2)?  I don't think making it a GTY root is necessary but
> > > > > > > I felt
> > > > > > > perhaps better to be safe than sorry.
> > > > > > > 
> > > > > > > Potentially another approach would be to use DECL_UID instead like
> > > > > > > how
> > > > > > > entity_map does; would that be preferable?
> > > > > > > 
> > > > > > > -- >8 --
> > > > > > > 
> > > > > > > I got notified by Linaro CI and by checking testresults that there
> > > > > > > seems
> > > > > > > to be some occasional failures in tpl-friend-4_b.C on some
> > > > > > > architectures
> > > > > > > and standards modes since r15-59-gb5f6a56940e708.  I haven't been
> > > > > > > able
> > > > > > > to reproduce but looking at the backtrace I suspect the issue is
> > > > > > > that
> > > > > > > we're adding to the 'imported_temploid_friend' map a decl that is
> > > > > > > ultimately discarded, which then has its address reused by a later
> > > > > > > decl
> > > > > > > causing a failure in the assert in 'set_originating_module'.
> > > > > > > 
> > > > > > > This patch attempts to fix the issue in two ways: by ensuring that
> > > > > > > we
> > > > > > > only store the decl if we know it's a new decl (and hence won't be
> > > > > > > discarded), and by making the imported_temploid_friends map a GTY
> > > > > > > root
> > > > > > > so that even if the decl does get discarded later the address
> > > > > > > isn't
> > > > > > > reused.
> > > > > > > 
> > > > > > > gcc/cp/ChangeLog:
> > > > > > > 
> > > > > > >   * module.cc (imported_temploid_friends): Mark GTY, and...
> > > > > > >   (init_modules): ...allocate from GGC.
> > > > > > >   (trees_in::decl_value): Only write to
> > > > > > > imported_temploid_friends
> > > > > > >   for new decls.
> > > > > > > 
> > > > > > > Signed-off-by: Nathaniel Shead 
> > > > > > > ---
> > > > > > >gcc/cp/module.cc | 7 ---
> > > > > > >1 file changed, 4 insertions(+), 3 deletions(-)
> > > > > > > 
> > > > > > > diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> > > > > > > index 5b8ff5bc483..37d38bb9654 100644
> > > > > > > --- a/gcc/cp/module.cc
> > > > > > > +++ b/gcc/cp/module.cc
> > > > > > > @@ -2731,7 +2731,7 @@ static keyed_map_t *keyed_table;
> > > > > > >   need to be attached to the same module as the temploid.
> > > > > > > This maps
> > > > > > >   these decls to the temploid they are instantiated them, as
> > > > > > > there is
> > > > > > >   no other easy way to get this information.  */
> > > > > > > -static hash_map *imported_temploid_friends;
> > > > > > > +static GTY(()) hash_map *imported_temploid_friends;
> > > > > > >
> > > > > > > //
> > > > > > >/* Tree streaming.   The tree streaming is very specific to the
> > > > > > > tree
> > > > > > > @@ -8327,7 +8327,8 @@ trees_in::decl_value ()
> > > > > > >  if (TREE_CODE (inner) == FUNCTION_DECL
> > > > > > >  || TREE_CODE (inner) == TYP

Re: [PATCH v2] Fix auto deduction for template specialization scopes [PR114915]

2024-05-06 Thread Patrick Palka
On Sat, 4 May 2024, Seyed Sajad Kahani wrote:

> The limitations of the initial patch (checking specializiation template 
> usage), have been discussed.
> 
> > I realized that for the case where we have a member function template
> > of a class template, and a specialization of the enclosing class only
> > (like below),
> >
> > template <>
> > template 
> > void S::f() {
> >   // some constrained auto
> > }
> >
> > When using S::f, DECL_TEMPLATE_INFO(fn) is non-zero, and
> > DECL_TEMPLATE_SPECIALIZATION(fn) is zero, while
> > DECL_TEMPLATE_SPECIALIZATION(DECL_TI_TEMPLATE(fn)) is non-zero.
> > So it means that the patch will extract DECL_TI_ARGS(fn) as
> > outer_targs, and it would be   while the type of the
> > constrained auto will be as template  ... and will not be
> > dependent on the parameters of the enclosing class.
> > This means that again (outer_targs + targs) will have more depth than
> > auto_node levels.
> > This means that for the case where the function is not an explicit
> > specialization, but it is defined in an explicitly specialized scope,
> > the patch will not work.

Ah yes, good point!  This demonstrates that it doesn't suffice to
handle the TEMPLATE_TYPE_ORIG_LEVEL == 1 case contrary to what I
suggested earlier.

> 
> As described in more detail below, this patch attempts to resolve this issue 
> by trimming full_targs.
> 
> > > Another more context-unaware approach to fix this might be to only
> > > use the innermost level from 'full_targs' for satisfaction if
> > > TEMPLATE_TYPE_ORIG_LEVEL is 1 (which means this constrained auto
> > > appeared in a context that doesn't have template parameters such as an
> > > explicit specialization or ordinary non-template function, and so
> > > only the level corresponding to the deduced type is needed for
> > > satisfaction.)
> > >
> > > Generalizing on that, another approach might be to handle missing_levels 
> > > < 0
> > > by removing -missing_levels from full_targs via 
> > > get_innermost_template_args.
> > > But AFAICT it should suffice to handle the TEMPLATE_TYPE_ORIG_LEVEL == 1
> > > case specifically.
> >
> > I was unable to understand why you think that it might not handle
> > TEMPLATE_TYPE_ORIG_LEVEL > 1 cases, so I tried to formulate my
> > reasoning as follows.

Yes, sorry about that misleading suggestion.

> >
> > Assuming contexts adc_variable_type, adc_return_type, adc_decomp_type:
> > For any case where missing_level < 0, it means that the type depends
> > on fewer levels than the template arguments used to materialize it.
> > This can only happen when the type is defined in an explicit
> > specialization scope. This explicit specialization might not occur in
> > its immediate scope.
> > Note that partial specialization (while changing the set of
> > parameters) cannot reduce the number of levels for the type.
> > Because of the fact that the enclosing scope of any explicit
> > specialization is explicitly specialized
> > (https://eel.is/c++draft/temp.expl.spec#16), the type will not depend
> > on template parameters outside of its innermost explicit specialized
> > scope.
> > Assuming that there are no real missing levels, by removing those
> > levels, missing_level should be = 0. As a result, by roughly doing
> >
> > if (missing_levels < 0) {
> >   tree trimmed_full_args = get_innermost_template_args(full_targs,
> > TEMPLATE_TYPE_ORIG_LEVEL(auto_node));
> >   full_targs = trimmed_full_args;
> > }
> > in pt.cc:31262, where we calculate and check missing_levels, we would
> > be able to fix the errors.
> > Note that, for the case where there are real missing levels, we are
> > putting irrelevant template arguments for the missing levels instead
> > of make_tree_vec(0). By this change:
> > - If the type is independent of those missing levels: it works fine either 
> > way.
> > - If the type is dependent on those missing levels: Instead of raising
> > an ICE, the compiler exhibits undefined behavior.

Makes sense.

> ---
>  gcc/cp/pt.cc  | 14 ++--
>  .../g++.dg/cpp2a/concepts-placeholder14.C | 19 +++
>  .../g++.dg/cpp2a/concepts-placeholder15.C | 15 +
>  .../g++.dg/cpp2a/concepts-placeholder16.C | 33 +++
>  4 files changed, 78 insertions(+), 3 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
> 
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 3b2106dd3..bdf03a1a7 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -31044,7 +31044,8 @@ unparenthesized_id_or_class_member_access_p (tree 
> init)
> OUTER_TARGS is used during template argument deduction (context == 
> adc_unify)
> to properly substitute the result.  It's also used in the adc_unify and
> adc_requirement contexts to communicate the necessary template arguments
> -   to satisfaction.  

Re: [PATCH] Fix auto deduction for template specialization scopes [114915].

2024-05-03 Thread Patrick Palka
Thanks for the patch!

On Wed, 1 May 2024, Seyed Sajad Kahani wrote:

> When deducing auto for `adc_return_type`, `adc_variable_type`, and 
> `adc_decomp_type` contexts (at the usage time), we try to resolve the 
> outermost template arguments to be used for satisfaction. This is done by one 
> of the following, depending on the scope:
> 
> 1. Checking the `DECL_TEMPLATE_INFO` of the current function scope and 
> extracting DECL_TI_ARGS from it for function scope deductions (pt.cc:31236).
> 2. Checking the `DECL_TEMPLATE_INFO` of the declaration (alongside with other 
> conditions) for non-function scope variable declaration deductions 
> (decl.cc:8527).
> 
> Then, we do not retrieve the deeper layers of the template arguments; 
> instead, we fill the missing levels with dummy levels (pt.cc:31260).
> 
> The problem (that is shown in PR114915) is that we do not consider the case 
> where the deduction happens in a template specialization scope. In this case, 
> the type is not dependent on the outermost template arguments (which are the 
> specialization arguments). Yet, we still resolve the outermost template 
> arguments, and then the number of layers in the template arguments exceeds 
> the number of levels in the type. This causes the missing levels to be 
> negative. This leads to the rejection of valid code and ICEs (like segfault) 
> in the release mode. In the debug mode, it is possible to show as an 
> assertion failure (when creating a tree_vec with a negative size).
> The code that generates the issue is added to the test suite as 
> `g++.dg/cpp2a/concepts-placeholder14.C`.
> 
> This patch fixes the issue by checking that the template usage, whose 
> arguments are going to be used for satisfaction, is not a partial or explicit 
> specialization (and therefore it is an implicit or explicit instantiation). 
> This check is done in the two only places that affect the `outer_targs` for 
> the mentioned contexts.
> 
> One might ask why this is not implemented as a simple `missing_level > 0` 
> check. The reason is that the recovery from the negative `missing_levels` 
> will not be easy, and it is not clear how to recover from it. Therefore, it 
> is better to prevent it from happening.
> ---
>  gcc/cp/decl.cc|  1 +
>  gcc/cp/pt.cc  | 16 ++-
>  .../g++.dg/cpp2a/concepts-placeholder14.C | 20 +++
>  3 files changed, 32 insertions(+), 5 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
> 
> diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> index 65ab64885..7e51f926e 100644
> --- a/gcc/cp/decl.cc
> +++ b/gcc/cp/decl.cc
> @@ -8527,6 +8527,7 @@ cp_finish_decl (tree decl, tree init, bool 
> init_const_expr_p,
>if (PLACEHOLDER_TYPE_CONSTRAINTS_INFO (auto_node)
> && DECL_LANG_SPECIFIC (decl)
> && DECL_TEMPLATE_INFO (decl)
> +   && DECL_USE_TEMPLATE (decl) != 2

We should check !DECL_TEMPLATE_SPECIALIZATION instead of checking
DECL_USE_TEMPLATE directly.

And since DECL_TEMPLATE_SPECIALIZATION is true for both partial and
explicit specializations, I think we should check !in_template_context
as well in order to single out explicit specializations?

> && !DECL_FUNCTION_SCOPE_P (decl))
>   /* The outer template arguments might be needed for satisfaction.
>  (For function scope variables, do_auto_deduction will obtain the
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 3b2106dd3..fd646d873 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -31044,7 +31044,8 @@ unparenthesized_id_or_class_member_access_p (tree 
> init)
> OUTER_TARGS is used during template argument deduction (context == 
> adc_unify)
> to properly substitute the result.  It's also used in the adc_unify and
> adc_requirement contexts to communicate the necessary template arguments
> -   to satisfaction.  OUTER_TARGS is ignored in other contexts.
> +   to satisfaction.  OUTER_TARGS will be used for other contexts if it is a
> +   function scope deduction. Otherwise it is ignored.
>  
> Additionally for adc_unify contexts TMPL is the template for which TYPE
> is a template parameter type.
> @@ -31235,8 +31236,11 @@ do_auto_deduction (tree type, tree init, tree 
> auto_node,
>   if (tree fn = current_function_decl)
> if (DECL_TEMPLATE_INFO (fn) || LAMBDA_FUNCTION_P (fn))
>   {
> -   outer_targs = DECL_TEMPLATE_INFO (fn)
> - ? DECL_TI_ARGS (fn) : NULL_TREE;
> +   outer_targs = NULL_TREE; 
> +   if (DECL_TEMPLATE_INFO (fn) && DECL_USE_TEMPLATE (fn) != 2)
> +   {
> +   outer_targs = DECL_TI_ARGS (fn);
> +   }

Same here.

> if (LAMBDA_FUNCTION_P (fn))
>   {
> /* As in satisfy_declaration_constraints.  */
> @@ -31260,8 +31264,10 @@ do_auto_deduction (tree type, tree init, tree 
> auto_node,
>these missing levels, but this hack 

[PATCH] c++: replace tf_norm with a local flag

2024-05-03 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
for trunk?

-- >8 --

The tf_norm flag controlling whether to build diagnostic information
during constraint normalization doesn't need to be a global tsubst flag,
and is confusingly named.  This patch replaces it with a boolean flag
local to normalization.

gcc/cp/ChangeLog:

* constraint.cc (norm_info::norm_info): Take a boolean parameter
instead of tsubst_flags_t.
(norm_info::generate_diagnostics): Turn this predicate function
into a data member.
(normalize_logical_operation): Adjust after norm_info changes.
(normalize_concept_check): Likewise.
(normalize_atom): Likewise.
(get_normalized_constraints_from_info): Likewise.
(normalize_concept_definition): Likewise.
(normalize_constraint_expression): Likewise.
(normalize_placeholder_type_constraints): Likewise.
(satisfy_nondeclaration_constraints): Likewise.
* cp-tree.h (enum tsubst_flags): Remove tf_norm.
---
 gcc/cp/constraint.cc | 40 
 gcc/cp/cp-tree.h |  3 +--
 2 files changed, 21 insertions(+), 22 deletions(-)

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 8a3b5d80ba7..3f0dab79bcd 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -622,33 +622,29 @@ parameter_mapping_equivalent_p (tree t1, tree t2)
 
 struct norm_info : subst_info
 {
-  explicit norm_info (tsubst_flags_t cmp)
-: norm_info (NULL_TREE, cmp)
+  explicit norm_info (bool diag)
+: norm_info (NULL_TREE, diag)
   {}
 
   /* Construct a top-level context for DECL.  */
 
-  norm_info (tree in_decl, tsubst_flags_t complain)
-: subst_info (tf_warning_or_error | complain, in_decl)
+  norm_info (tree in_decl, bool diag)
+: subst_info (tf_warning_or_error, in_decl),
+  generate_diagnostics (diag)
   {
 if (in_decl)
   {
initial_parms = DECL_TEMPLATE_PARMS (in_decl);
-   if (generate_diagnostics ())
+   if (generate_diagnostics)
  context = build_tree_list (NULL_TREE, in_decl);
   }
 else
   initial_parms = current_template_parms;
   }
 
-  bool generate_diagnostics() const
-  {
-return complain & tf_norm;
-  }
-
   void update_context(tree expr, tree args)
   {
-if (generate_diagnostics ())
+if (generate_diagnostics)
   {
tree map = build_parameter_mapping (expr, args, ctx_parms ());
context = tree_cons (map, expr, context);
@@ -679,6 +675,10 @@ struct norm_info : subst_info
  template parameters of ORIG_DECL.  */
 
   tree initial_parms = NULL_TREE;
+
+  /* Whether to build diagnostic information during normalization.  */
+
+  bool generate_diagnostics;
 };
 
 static tree normalize_expression (tree, tree, norm_info);
@@ -693,7 +693,7 @@ normalize_logical_operation (tree t, tree args, tree_code 
c, norm_info info)
   tree t1 = normalize_expression (TREE_OPERAND (t, 1), args, info);
 
   /* Build a new info object for the constraint.  */
-  tree ci = info.generate_diagnostics()
+  tree ci = info.generate_diagnostics
 ? build_tree_list (t, info.context)
 : NULL_TREE;
 
@@ -777,7 +777,7 @@ normalize_concept_check (tree check, tree args, norm_info 
info)
   if (!norm_cache)
 norm_cache = hash_table::create_ggc (31);
   norm_entry *entry = nullptr;
-  if (!info.generate_diagnostics ())
+  if (!info.generate_diagnostics)
 {
   /* Cache the normal form of the substituted concept-id (when not
 diagnosing).  */
@@ -831,7 +831,7 @@ normalize_atom (tree t, tree args, norm_info info)
   if (info.in_decl && concept_definition_p (info.in_decl))
 ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (atom) = true;
 
-  if (!info.generate_diagnostics ())
+  if (!info.generate_diagnostics)
 {
   /* Cache the ATOMIC_CONSTRs that we return, so that sat_hasher::equal
 later can cheaply compare two atoms using just pointer equality.  */
@@ -910,7 +910,7 @@ get_normalized_constraints_from_info (tree ci, tree 
in_decl, bool diag = false)
 
   /* Substitution errors during normalization are fatal.  */
   ++processing_template_decl;
-  norm_info info (in_decl, diag ? tf_norm : tf_none);
+  norm_info info (in_decl, diag);
   tree t = get_normalized_constraints (CI_ASSOCIATED_CONSTRAINTS (ci), info);
   --processing_template_decl;
 
@@ -1012,7 +1012,7 @@ normalize_concept_definition (tree tmpl, bool diag)
   gcc_assert (TREE_CODE (tmpl) == TEMPLATE_DECL);
   tree def = get_concept_definition (DECL_TEMPLATE_RESULT (tmpl));
   ++processing_template_decl;
-  norm_info info (tmpl, diag ? tf_norm : tf_none);
+  norm_info info (tmpl, diag);
   tree norm = get_normalized_constraints (def, info);
   --processing_template_decl;
 
@@ -1035,7 +1035,7 @@ normalize_constraint_expression (tree expr, norm_info 
info)
   if (!expr || expr == error_mark_node)
 return expr;
 
-  if (!info.generate_diagnostics ())
+  if (!info.generate_diagnostics)
 if (tree *p = 

Re: [PATCH] c++: 'typename T::X' vs 'struct T::X' lookup [PR109420]

2024-05-03 Thread Patrick Palka
Hey Andrew,

On Wed, 5 Apr 2023, Andrew Pinski wrote:

> On Wed, Apr 5, 2023 at 10:32 AM Patrick Palka via Gcc-patches
>  wrote:
> >
> > On Wed, 5 Apr 2023, Patrick Palka wrote:
> >
> > > r13-6098-g46711ff8e60d64 made make_typename_type no longer ignore
> > > non-types during the lookup, unless the TYPENAME_TYPE in question was
> > > followed by the :: scope resolution operator.  But there is another
> > > exception to this rule: we need to ignore non-types during the lookup
> > > also if the TYPENAME_TYPE was named with a tag other than 'typename',
> > > such as 'struct' or 'enum', as per [dcl.type.elab]/5.
> > >
> > > This patch implements this additional exception.  It occurred to me that
> > > the tf_qualifying_scope flag is probably unnecessary if we'd use the
> > > scope_type tag more thoroughly, but that requires parser changes that
> > > are probably too risky at this stage.  (I'm working on addressing the
> > > FIXME/TODOs here for GCC 14.)
> > >
> > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > > trunk?
> > >
> > >   PR c++/109420
> > >
> > > gcc/cp/ChangeLog:
> > >
> > >   * decl.cc (make_typename_type): Also ignore non-types during
> > >   the lookup if tag_type is something other than none_type or
> > >   typename_type.
> > >   * pt.cc (tsubst) : Pass class_type or
> > >   enum_type as tag_type to make_typename_type as appropriate
> > >   instead of always passing typename_type.
> > >
> > > gcc/testsuite/ChangeLog:
> > >
> > >   * g++.dg/template/typename27.C: New test.
> > > ---
> > >  gcc/cp/decl.cc |  9 -
> > >  gcc/cp/pt.cc   |  9 -
> > >  gcc/testsuite/g++.dg/template/typename27.C | 19 +++
> > >  3 files changed, 35 insertions(+), 2 deletions(-)
> > >  create mode 100644 gcc/testsuite/g++.dg/template/typename27.C
> > >
> > > diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> > > index 5369714f9b3..a0a20c5accc 100644
> > > --- a/gcc/cp/decl.cc
> > > +++ b/gcc/cp/decl.cc
> > > @@ -4307,7 +4307,14 @@ make_typename_type (tree context, tree name, enum 
> > > tag_types tag_type,
> > >   lookup will stop when we hit a dependent base.  */
> > >if (!dependent_scope_p (context))
> > >  {
> > > -  bool want_type = (complain & tf_qualifying_scope);
> > > +  /* As per [dcl.type.elab]/5 and [temp.res.general]/3, ignore 
> > > non-types if
> > > +  the tag corresponds to a class-key or 'enum' (or is scope_type), 
> > > or if
> > > +  this typename is followed by :: as per 
> > > [basic.lookup.qual.general]/1.
> > > +  TODO: If we'd set the scope_type tag accurately on all 
> > > TYPENAME_TYPEs
> > > +  that are followed by :: then we wouldn't need the 
> > > tf_qualifying_scope
> > > +  flag.  */
> > > +  bool want_type = (tag_type != none_type && tag_type != 
> > > typename_type)
> > > + || (complain & tf_qualifying_scope);
> >
> > Here's v2 which just slightly improves this comment.  I reckon 
> > [basic.lookup.elab]
> > is a better reference than [dcl.type.elab]/5 for justifying why the
> > lookup should be type-only for class-key and 'enum' TYPENAME_TYPEs.
> >
> > -- >8 --
> >
> > PR c++/109420
> >
> > gcc/cp/ChangeLog:
> >
> > * decl.cc (make_typename_type): Also ignore non-types during the
> > lookup if tag_type corresponds to an elaborated-type-specifier.
> > * pt.cc (tsubst) : Pass class_type or
> > enum_type as tag_type to make_typename_type as appropriate
> > instead of always passing typename_type.
> >
> > gcc/testsuite/ChangeLog:
> >
> > * g++.dg/template/typename27.C: New test.
> > ---
> >  gcc/cp/decl.cc | 12 +++-
> >  gcc/cp/pt.cc   |  9 -
> >  gcc/testsuite/g++.dg/template/typename27.C | 19 +++
> >  3 files changed, 38 insertions(+), 2 deletions(-)
> >  create mode 100644 gcc/testsuite/g++.dg/template/typename27.C
> >
> > diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> > index 5369714f9b3..772c059dc2c 100644
> > --- a/gcc/cp/decl.cc
> > +++ b/gcc/cp/decl.cc
> > @@ -4

Re: [PATCH 2/2] c++: remove lookup_template_class's entering_scope flag

2024-05-02 Thread Patrick Palka
On Wed, 1 May 2024, Jason Merrill wrote:

> On 5/1/24 13:40, Patrick Palka wrote:
> > On Wed, 1 May 2024, Jason Merrill wrote:
> > 
> > > On 5/1/24 12:41, Patrick Palka wrote:
> > > > On Fri, 2 Feb 2024, Patrick Palka wrote:
> > > > 
> > > > > Bootstrapped and regtested on x86_64-pc-linux, does this look like
> > > > > an improvement?  This is not a bugfix and barely related to the
> > > > > previous
> > > > > patch, but the previous patch's new use of entering_scope=true
> > > > > motivated
> > > > > me to submit this patch since it seems like a nice simplification.
> > > > 
> > > > Ping, now that stage 1 is open.
> > > 
> > > Thanks for the ping.  The earlier message isn't showing up in Thunderbird
> > > for
> > > some reason, though I see it in the gmail web interface...
> > 
> > Ah, weird.  No worries, this patch was very much stage 1 material anyway.
> > 
> > > 
> > > > > @@ -16771,9 +16722,10 @@ tsubst (tree t, tree args, tsubst_flags_t
> > > > > complain, tree in_decl)
> > > > >   ctx = TREE_VEC_ELT (ctx, 0);
> > > > > }
> > > > >   else
> > > > > -   ctx = tsubst_aggr_type (ctx, args,
> > > > > -   complain | tf_qualifying_scope,
> > > > > -   in_decl, /*entering_scope=*/1);
> > > > > +   {
> > > > > + ctx = tsubst_scope (ctx, args, complain, in_decl);
> > > 
> > > Why is this one tsubst_scope while the others are all plain tsubst?
> > 
> > Ah, just because the call to tsubst_aggr_type being replace passes
> > tf_qualifying_scope already, so we might as well use tsubst_scope
> > as shorthand.
> > 
> > > Do we want a tsubst_entering_scope function?
> > 
> > Which is just shorthand for tsubst + adjust_type_for_entering_scope?
> 
> That's what I was thinking.
> 
> > Sure, though I was wondering if we eventually might want to get rid of
> > the distinction between the primary template type A and the generic
> > instantiation A, and we could treat this as an incremental step
> > towards that (then we'd just eventually remove the
> > adjust_type_for_entering_scope calls and keep the tsubst calls).
> 
> I don't think we want that; having the distinction helps to avoid wrongly
> looking up members of the primary template in contexts that shouldn't be able
> to.

Makes sense.  How does the following look?

The name tsubst_entering_scope sounds confusingly similar to
tsubst_scope, but I can't think of a better name for it or for
adjust_type_for_entering_scope :/

-- >8 --

Subject: [PATCH] c++: remove lookup_template_class's entering_scope flag
gcc/cp/ChangeLog:

* coroutines.cc (instantiate_coro_traits): Adjust call to
lookup_template_class.
(instantiate_coro_handle_for_promise_type): Likewise.
* cp-tree.h (adjust_type_for_entering_scope): Declare.
(lookup_template_class): Adjust declaration.
* decl.cc (make_typename_type): Adjust call to
lookup_template_class. Likewise.
(get_tuple_size): Likewise.
(get_tuple_element_type): Likewise.
* pt.cc (adjust_type_for_entering_scope): Define.
(tsubst_entering_scope): Define.
(lookup_template_class): Remove entering_scope parameter.
Replace tsubst_aggr_type call with tsubst_entering_scope.
(tsubst_aggr_type): Remove.
(tsubst_aggr_type_1): Inline into tsubst.
(tsubst_function_decl): Replace tsubst_aggr_type call
with tsubst_entering_scope.
(tsubst_template_decl): Likewise.
(tsubst_decl): Likewise.
(tsubst) :
Inlined from tsubst_aggr_type_1.
: Adjust calls to
lookup_template_class.
: Replace tsubst_aggr_type call with
tsubst_scope followed by adjust_type_for_entering_scope.
: Replace tsubst_aggr_type
call with tsubst_entering_scope.
Increment processing_template_decl when substituting the
context.
(tsubst_expr) : Replace tsubst_aggr_type
call with tsubst_entering_scope.
: Likewise.
(instantiate_template): Likewise.
(resolve_typename_type): Adjust lookup_template_class call
and call adjust_type_for_entering_scope afterward.
(listify): Adjust lookup_template_class call.
(alias_ctad_tweaks): Likewise.
* semantics.cc (finish_template_type): Adjust lookup_template_class
call and maybe call adjust_type_for_entering_scope afterward.
---
 gcc/cp/coroutines.cc |   4 +-
 gcc/cp/cp-tree.h

Re: [PATCH v14 21/26] c++: Implement __rank built-in trait

2024-05-02 Thread Patrick Palka
On Tue, 30 Apr 2024, Jason Merrill wrote:

> On 2/28/24 11:26, Ken Matsui wrote:
> > This patch implements built-in trait for std::rank.
> 
> __rank seems too short, maybe __array_rank?
> 
> Actually, it occurs to me that perhaps we should have been adding __builtin to
> all of these rather than just __ and the library trait name.  I guess it's too
> late to do that for the GCC 14 traits, but we could do it for this group?

Clang already implements many of these built-in, without using
"__builtin" in their name.  Shouldn't we be consistent with Clang where
we can?

> 
> > gcc/cp/ChangeLog:
> > 
> > * cp-trait.def: Define __rank.
> > * constraint.cc (diagnose_trait_expr): Handle CPTK_RANK.
> > * semantics.cc (trait_expr_value): Likewise.
> > (finish_trait_expr): Likewise.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/ext/has-builtin-1.C: Test existence of __rank.
> > * g++.dg/ext/rank.C: New test.
> > 
> > Signed-off-by: Ken Matsui 
> > ---
> >   gcc/cp/constraint.cc |  3 +++
> >   gcc/cp/cp-trait.def  |  1 +
> >   gcc/cp/semantics.cc  | 23 ---
> >   gcc/testsuite/g++.dg/ext/has-builtin-1.C |  3 +++
> >   gcc/testsuite/g++.dg/ext/rank.C  | 24 
> >   5 files changed, 51 insertions(+), 3 deletions(-)
> >   create mode 100644 gcc/testsuite/g++.dg/ext/rank.C
> > 
> > diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> > index 000df847342..23ea66d9c12 100644
> > --- a/gcc/cp/constraint.cc
> > +++ b/gcc/cp/constraint.cc
> > @@ -3870,6 +3870,9 @@ diagnose_trait_expr (tree expr, tree args)
> >   case CPTK_IS_VOLATILE:
> > inform (loc, "  %qT is not a volatile type", t1);
> > break;
> > +case CPTK_RANK:
> > +  inform (loc, "  %qT cannot yield a rank", t1);
> > +  break;
> >   case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
> > inform (loc, "  %qT is not a reference that binds to a temporary "
> >   "object of type %qT (direct-initialization)", t1, t2);
> > diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
> > index 2d1cb7c227c..85056c8140b 100644
> > --- a/gcc/cp/cp-trait.def
> > +++ b/gcc/cp/cp-trait.def
> > @@ -99,6 +99,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE,
> > "__is_trivially_copyable", 1)
> >   DEFTRAIT_EXPR (IS_UNBOUNDED_ARRAY, "__is_unbounded_array", 1)
> >   DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
> >   DEFTRAIT_EXPR (IS_VOLATILE, "__is_volatile", 1)
> > +DEFTRAIT_EXPR (RANK, "__rank", 1)
> >   DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY,
> > "__reference_constructs_from_temporary", 2)
> >   DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY,
> > "__reference_converts_from_temporary", 2)
> >   DEFTRAIT_TYPE (REMOVE_ALL_EXTENTS, "__remove_all_extents", 1)
> > diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> > index 45dc509855a..7242db75248 100644
> > --- a/gcc/cp/semantics.cc
> > +++ b/gcc/cp/semantics.cc
> > @@ -12550,6 +12550,9 @@ trait_expr_value (cp_trait_kind kind, tree type1,
> > tree type2)
> >   case CPTK_IS_DEDUCIBLE:
> > return type_targs_deducible_from (type1, type2);
> >   +/* __rank is handled in finish_trait_expr. */
> > +case CPTK_RANK:
> 
> This should have a gcc_unreachable.
> 
> > +
> >   #define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> >   case CPTK_##CODE:
> >   #include "cp-trait.def"
> > @@ -12622,7 +12625,10 @@ finish_trait_expr (location_t loc, cp_trait_kind
> > kind, tree type1, tree type2)
> > if (processing_template_decl)
> >   {
> > tree trait_expr = make_node (TRAIT_EXPR);
> > -  TREE_TYPE (trait_expr) = boolean_type_node;
> > +  if (kind == CPTK_RANK)
> > +   TREE_TYPE (trait_expr) = size_type_node;
> > +  else
> > +   TREE_TYPE (trait_expr) = boolean_type_node;
> > TRAIT_EXPR_TYPE1 (trait_expr) = type1;
> > TRAIT_EXPR_TYPE2 (trait_expr) = type2;
> > TRAIT_EXPR_KIND (trait_expr) = kind;
> > @@ -12714,6 +12720,7 @@ finish_trait_expr (location_t loc, cp_trait_kind
> > kind, tree type1, tree type2)
> >   case CPTK_IS_UNBOUNDED_ARRAY:
> >   case CPTK_IS_UNION:
> >   case CPTK_IS_VOLATILE:
> > +case CPTK_RANK:
> > break;
> > case CPTK_IS_LAYOUT_COMPATIBLE:
> > @@ -12745,8 +12752,18 @@ finish_trait_expr (location_t loc, cp_trait_kind
> > kind, tree type1, tree type2)
> > gcc_unreachable ();
> >   }
> >   -  tree val = (trait_expr_value (kind, type1, type2)
> > - ? boolean_true_node : boolean_false_node);
> > +  tree val;
> > +  if (kind == CPTK_RANK)
> > +{
> > +  size_t rank = 0;
> > +  for (; TREE_CODE (type1) == ARRAY_TYPE; type1 = TREE_TYPE (type1))
> > +   ++rank;
> > +  val = build_int_cst (size_type_node, rank);
> > +}
> > +  else
> > +val = (trait_expr_value (kind, type1, type2)
> > +  ? boolean_true_node : boolean_false_node);
> > +
> > return maybe_wrap_with_location (val, loc);
> >   }
> >   diff --git 

Re: [PATCH] c++/modules: Stream unmergeable temporaries by value again [PR114856]

2024-05-02 Thread Patrick Palka
On Thu, 2 May 2024, Nathaniel Shead wrote:

> Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk/14.2?
> 
> Another alternative would be to stream such !DECL_NAME temporaries with
> a merge key of MK_unique rather than attempting to find the matching
> (nonexistant) field of the class context.

Both approaches sound good to me, hard to say which one is preferable..

The handling of function-scope vs class-scope temporaries seems to start
diverging in:

@@ -8861,28 +8861,6 @@ trees_out::decl_node (tree decl, walk_kind ref)
   return false;
 }
 
!  tree ctx = CP_DECL_CONTEXT (decl);
!  depset *dep = NULL;
!  if (streaming_p ())
!dep = dep_hash->find_dependency (decl);
!  else if (TREE_CODE (ctx) != FUNCTION_DECL
!  || TREE_CODE (decl) == TEMPLATE_DECL
!  || DECL_IMPLICIT_TYPEDEF_P (decl)
!  || (DECL_LANG_SPECIFIC (decl)
!  && DECL_MODULE_IMPORT_P (decl)))
!{
!  auto kind = (TREE_CODE (decl) == NAMESPACE_DECL
!  && !DECL_NAMESPACE_ALIAS (decl)
!  ? depset::EK_NAMESPACE : depset::EK_DECL);
!  dep = dep_hash->add_dependency (decl, kind);
!}
!
!  if (!dep)
!{
!  /* Some internal entity of context.  Do by value.  */
!  decl_value (decl, NULL);
!  return false;
!}
 
   if (dep->get_entity_kind () == depset::EK_REDIRECT)
 {

where for a class-scope temporary we add a dependency for it, stream
it by reference, and then stream it by value separately, which seems
unnecessary.

So if we decide to keep the create_temporary_var change, we probably
would want to unify this code path's handling of temporaries (i.e.
don't add_dependency a temporary regardless of its context).

If we decide your partially revert the create_temporary_var change,
your patch LGTM.

> 
> -- >8 --
> 
> In r14-9266-g2823b4d96d9ec4 I gave all temporary vars a DECL_CONTEXT,
> including those at namespace or global scope, so that they could be
> properly merged across importers.  However, not all of these temporary
> vars are actually supposed to be mergeable.
> 
> For instance, in the attached testcase we have an unnamed temporary var
> used in the NSDMI of a class member, which cannot properly merged -- but
> it also doesn't need to be, as it'll be thrown away when the class type
> itself is merged anyway.
> 
> This patch reverts the change made above and instead makes a weaker
> adjustment that only causes temporary vars with linkage have a
> DECL_CONTEXT to merge from.  This way these unnamed, "unmergeable"
> temporaries are properly streamed by value again.
> 
>   PR c++/114856
> 
> gcc/cp/ChangeLog:
> 
>   * call.cc (make_temporary_var_for_ref_to_temp): Set context for
>   temporaries with linkage.
>   * init.cc (create_temporary_var): Revert to only set context
>   when in a function decl.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/modules/pr114856.h: New test.
>   * g++.dg/modules/pr114856_a.H: New test.
>   * g++.dg/modules/pr114856_b.C: New test.
> 
> Signed-off-by: Nathaniel Shead 
> ---
>  gcc/cp/call.cc|  1 +
>  gcc/cp/init.cc|  2 +-
>  gcc/testsuite/g++.dg/modules/pr114856.h   | 12 
>  gcc/testsuite/g++.dg/modules/pr114856_a.H |  5 +
>  gcc/testsuite/g++.dg/modules/pr114856_b.C |  5 +
>  5 files changed, 24 insertions(+), 1 deletion(-)
>  create mode 100644 gcc/testsuite/g++.dg/modules/pr114856.h
>  create mode 100644 gcc/testsuite/g++.dg/modules/pr114856_a.H
>  create mode 100644 gcc/testsuite/g++.dg/modules/pr114856_b.C
> 
> diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
> index dbdd7c29fe8..3b8889ac301 100644
> --- a/gcc/cp/call.cc
> +++ b/gcc/cp/call.cc
> @@ -13799,6 +13799,7 @@ make_temporary_var_for_ref_to_temp (tree decl, tree 
> type)
>  
>tree name = mangle_ref_init_variable (decl);
>DECL_NAME (var) = name;
> +  DECL_CONTEXT (var) = current_scope ();
>SET_DECL_ASSEMBLER_NAME (var, name);
>  }
>else
> diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
> index a93ce00800c..e758a8c8568 100644
> --- a/gcc/cp/init.cc
> +++ b/gcc/cp/init.cc
> @@ -4287,7 +4287,7 @@ create_temporary_var (tree type)
>TREE_USED (decl) = 1;
>DECL_ARTIFICIAL (decl) = 1;
>DECL_IGNORED_P (decl) = 1;
> -  DECL_CONTEXT (decl) = current_scope ();
> +  DECL_CONTEXT (decl) = current_function_decl;
>  
>return decl;
>  }
> diff --git a/gcc/testsuite/g++.dg/modules/pr114856.h 
> b/gcc/testsuite/g++.dg/modules/pr114856.h
> new file mode 100644
> index 000..b1a3c2cd834
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/modules/pr114856.h
> @@ -0,0 +1,12 @@
> +// PR c++/114856
> +
> +#include 
> +struct A {
> +  ~A();
> +};
> +struct V {
> +  V(std::initializer_list);
> +};
> +struct data {
> +  V v{{}};
> +};
> diff --git a/gcc/testsuite/g++.dg/modules/pr114856_a.H 
> b/gcc/testsuite/g++.dg/modules/pr114856_a.H
> new file mode 100644
> index 000..6195277dbde
> --- /dev/null

Re: [PATCH v2] c++/modules: Fix dangling pointer with imported_temploid_friends

2024-05-02 Thread Patrick Palka
On Wed, May 1, 2024 at 9:35 PM Nathaniel Shead
 wrote:
>
> On Thu, May 02, 2024 at 12:15:44AM +1000, Nathaniel Shead wrote:
> > On Wed, May 01, 2024 at 09:57:38AM -0400, Patrick Palka wrote:
> > >
> > > On Wed, 1 May 2024, Nathaniel Shead wrote:
> > >
> > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk (and
> > > > later 14.2)?  I don't think making it a GTY root is necessary but I felt
> > > > perhaps better to be safe than sorry.
> > > >
> > > > Potentially another approach would be to use DECL_UID instead like how
> > > > entity_map does; would that be preferable?
> > > >
> > > > -- >8 --
> > > >
> > > > I got notified by Linaro CI and by checking testresults that there seems
> > > > to be some occasional failures in tpl-friend-4_b.C on some architectures
> > > > and standards modes since r15-59-gb5f6a56940e708.  I haven't been able
> > > > to reproduce but looking at the backtrace I suspect the issue is that
> > > > we're adding to the 'imported_temploid_friend' map a decl that is
> > > > ultimately discarded, which then has its address reused by a later decl
> > > > causing a failure in the assert in 'set_originating_module'.
> > > >
> > > > This patch attempts to fix the issue in two ways: by ensuring that we
> > > > only store the decl if we know it's a new decl (and hence won't be
> > > > discarded), and by making the imported_temploid_friends map a GTY root
> > > > so that even if the decl does get discarded later the address isn't
> > > > reused.
> > > >
> > > > gcc/cp/ChangeLog:
> > > >
> > > >   * module.cc (imported_temploid_friends): Mark GTY, and...
> > > >   (init_modules): ...allocate from GGC.
> > > >   (trees_in::decl_value): Only write to imported_temploid_friends
> > > >   for new decls.
> > > >
> > > > Signed-off-by: Nathaniel Shead 
> > > > ---
> > > >  gcc/cp/module.cc | 7 ---
> > > >  1 file changed, 4 insertions(+), 3 deletions(-)
> > > >
> > > > diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> > > > index 5b8ff5bc483..37d38bb9654 100644
> > > > --- a/gcc/cp/module.cc
> > > > +++ b/gcc/cp/module.cc
> > > > @@ -2731,7 +2731,7 @@ static keyed_map_t *keyed_table;
> > > > need to be attached to the same module as the temploid.  This maps
> > > > these decls to the temploid they are instantiated them, as there is
> > > > no other easy way to get this information.  */
> > > > -static hash_map *imported_temploid_friends;
> > > > +static GTY(()) hash_map *imported_temploid_friends;
> > > >
> > > >  //
> > > >  /* Tree streaming.   The tree streaming is very specific to the tree
> > > > @@ -8327,7 +8327,8 @@ trees_in::decl_value ()
> > > >if (TREE_CODE (inner) == FUNCTION_DECL
> > > >|| TREE_CODE (inner) == TYPE_DECL)
> > > >  if (tree owner = tree_node ())
> > > > -  imported_temploid_friends->put (decl, owner);
> > > > +  if (is_new)
> > > > + imported_temploid_friends->put (decl, owner);
> > >
> > > Hmm, I'm not seeing this code path getting reached for tpl-friend-4_b.C.
> > > It seems we're instead adding to imported_temploid_friends from
> > > propagate_defining_module, during tsubst_friend_function.
> > >
> > > What seems to be happening is that we we first tsubst_friend_function
> > > 'foo' from TPL, and then we tsubst_friend_function 'foo' from 
> > > DEF,
> > > which ends up calling duplicate_decls, which ggc_frees this 'foo'
> > > redeclaration that is still present in the imported_temploid_friends map.
> > >
> > > So I don't think marking imported_temploid_friends as a GC root would
> > > help with this situation.  If we want to keep imported_temploid_friends
> > > as a tree -> tree map, I think we just need to ensure that a decl
> > > is removed from the map upon getting ggc_free'd from e.g.  
> > > duplicate_decls.
> > >
> > > But it seems simpler to use DECL_UID as the key instead, since those
> > > never get reused even after the decl gets ggc_free'd IIUC.
> > >
> >
> > Ah right, thanks for digging into that further.  Yup OK, I think
> > probably the 

Re: [PATCH] c++: problematic assert in reference_binding [PR113141]

2024-05-01 Thread Patrick Palka
On Wed, 1 May 2024, Patrick Palka wrote:

> On Wed, 1 May 2024, Jason Merrill wrote:
> 
> > On 4/12/24 13:22, Patrick Palka wrote:
> > > On Fri, 12 Apr 2024, Jason Merrill wrote:
> > > 
> > > > On 3/26/24 09:44, Patrick Palka wrote:
> > > > > On Thu, 7 Mar 2024, Jason Merrill wrote:
> > > > > 
> > > > > > On 1/29/24 17:42, Patrick Palka wrote:
> > > > > > > On Mon, 29 Jan 2024, Patrick Palka wrote:
> > > > > > > 
> > > > > > > > On Fri, 26 Jan 2024, Jason Merrill wrote:
> > > > > > > > 
> > > > > > > > > On 1/26/24 17:11, Jason Merrill wrote:
> > > > > > > > > > On 1/26/24 16:52, Jason Merrill wrote:
> > > > > > > > > > > On 1/25/24 14:18, Patrick Palka wrote:
> > > > > > > > > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does
> > > > > > > > > > > > this
> > > > > > > > > > > > look
> > > > > > > > > > > > OK for trunk/13?  This isn't a very satisfactory fix, 
> > > > > > > > > > > > but
> > > > > > > > > > > > at
> > > > > > > > > > > > least
> > > > > > > > > > > > it safely fixes these testcases I guess.  Note that
> > > > > > > > > > > > there's
> > > > > > > > > > > > implementation disagreement about the second testcase, 
> > > > > > > > > > > > GCC
> > > > > > > > > > > > always
> > > > > > > > > > > > accepted it but Clang/MSVC/icc reject it.
> > > > > > > > > > > 
> > > > > > > > > > > Because of trying to initialize int& from {c}; removing 
> > > > > > > > > > > the
> > > > > > > > > > > extra
> > > > > > > > > > > braces
> > > > > > > > > > > makes it work everywhore.
> > > > > > > > > > > 
> > > > > > > > > > > https://eel.is/c++draft/dcl.init#list-3.10 says that we
> > > > > > > > > > > always
> > > > > > > > > > > generate a
> > > > > > > > > > > prvalue in this case, so perhaps we shouldn't recalculate 
> > > > > > > > > > > if
> > > > > > > > > > > the
> > > > > > > > > > > initializer is an init-list?
> > > > > > > > > > 
> > > > > > > > > > ...but it seems bad to silently bind a const int& to a 
> > > > > > > > > > prvalue
> > > > > > > > > > instead
> > > > > > > > > > of
> > > > > > > > > > directly to the reference returned by the operator, as clang
> > > > > > > > > > does
> > > > > > > > > > if
> > > > > > > > > > we add
> > > > > > > > > > const to the second testcase, so I think there's a defect in
> > > > > > > > > > the
> > > > > > > > > > standard
> > > > > > > > > > here.
> > > > > > > > > 
> > > > > > > > > Perhaps bullet 3.9 should change to "...its referenced type is
> > > > > > > > > reference-related to E or scalar, ..."
> > > > > > > > > 
> > > > > > > > > > Maybe for now also disable the maybe_valid heuristics in the
> > > > > > > > > > case
> > > > > > > > > > of
> > > > > > > > > > an
> > > > > > > > > > init-list?
> > > > > > > > > > 
> > > > > > > > > > > The first testcase is special because it's a C-style cast;
> > > > > > > > > > > seems
> > > > > > > > > > > like the
> > > > > > > > > > > maybe_valid = false heuristics should be disabled if
> > >

Re: [PATCH] c++: problematic assert in reference_binding [PR113141]

2024-05-01 Thread Patrick Palka
On Wed, 1 May 2024, Jason Merrill wrote:

> On 4/12/24 13:22, Patrick Palka wrote:
> > On Fri, 12 Apr 2024, Jason Merrill wrote:
> > 
> > > On 3/26/24 09:44, Patrick Palka wrote:
> > > > On Thu, 7 Mar 2024, Jason Merrill wrote:
> > > > 
> > > > > On 1/29/24 17:42, Patrick Palka wrote:
> > > > > > On Mon, 29 Jan 2024, Patrick Palka wrote:
> > > > > > 
> > > > > > > On Fri, 26 Jan 2024, Jason Merrill wrote:
> > > > > > > 
> > > > > > > > On 1/26/24 17:11, Jason Merrill wrote:
> > > > > > > > > On 1/26/24 16:52, Jason Merrill wrote:
> > > > > > > > > > On 1/25/24 14:18, Patrick Palka wrote:
> > > > > > > > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does
> > > > > > > > > > > this
> > > > > > > > > > > look
> > > > > > > > > > > OK for trunk/13?  This isn't a very satisfactory fix, but
> > > > > > > > > > > at
> > > > > > > > > > > least
> > > > > > > > > > > it safely fixes these testcases I guess.  Note that
> > > > > > > > > > > there's
> > > > > > > > > > > implementation disagreement about the second testcase, GCC
> > > > > > > > > > > always
> > > > > > > > > > > accepted it but Clang/MSVC/icc reject it.
> > > > > > > > > > 
> > > > > > > > > > Because of trying to initialize int& from {c}; removing the
> > > > > > > > > > extra
> > > > > > > > > > braces
> > > > > > > > > > makes it work everywhore.
> > > > > > > > > > 
> > > > > > > > > > https://eel.is/c++draft/dcl.init#list-3.10 says that we
> > > > > > > > > > always
> > > > > > > > > > generate a
> > > > > > > > > > prvalue in this case, so perhaps we shouldn't recalculate if
> > > > > > > > > > the
> > > > > > > > > > initializer is an init-list?
> > > > > > > > > 
> > > > > > > > > ...but it seems bad to silently bind a const int& to a prvalue
> > > > > > > > > instead
> > > > > > > > > of
> > > > > > > > > directly to the reference returned by the operator, as clang
> > > > > > > > > does
> > > > > > > > > if
> > > > > > > > > we add
> > > > > > > > > const to the second testcase, so I think there's a defect in
> > > > > > > > > the
> > > > > > > > > standard
> > > > > > > > > here.
> > > > > > > > 
> > > > > > > > Perhaps bullet 3.9 should change to "...its referenced type is
> > > > > > > > reference-related to E or scalar, ..."
> > > > > > > > 
> > > > > > > > > Maybe for now also disable the maybe_valid heuristics in the
> > > > > > > > > case
> > > > > > > > > of
> > > > > > > > > an
> > > > > > > > > init-list?
> > > > > > > > > 
> > > > > > > > > > The first testcase is special because it's a C-style cast;
> > > > > > > > > > seems
> > > > > > > > > > like the
> > > > > > > > > > maybe_valid = false heuristics should be disabled if
> > > > > > > > > > c_cast_p.
> > > > > > > 
> > > > > > > Thanks a lot for the pointers.  IIUC c_cast_p and
> > > > > > > LOOKUP_SHORTCUT_BAD_CONVS
> > > > > > > should already be mutually exclusive, since the latter is set only
> > > > > > > when
> > > > > > > computing argument conversions, so it shouldn't be necessary to
> > > > > > > check
> > > > > > > c_cast_p.
> > > > > > > 
> > > > > > >

Re: [PATCH 2/2] c++: remove lookup_template_class's entering_scope flag

2024-05-01 Thread Patrick Palka
On Wed, 1 May 2024, Jason Merrill wrote:

> On 5/1/24 12:41, Patrick Palka wrote:
> > On Fri, 2 Feb 2024, Patrick Palka wrote:
> > 
> > > Bootstrapped and regtested on x86_64-pc-linux, does this look like
> > > an improvement?  This is not a bugfix and barely related to the previous
> > > patch, but the previous patch's new use of entering_scope=true motivated
> > > me to submit this patch since it seems like a nice simplification.
> > 
> > Ping, now that stage 1 is open.
> 
> Thanks for the ping.  The earlier message isn't showing up in Thunderbird for
> some reason, though I see it in the gmail web interface...

Ah, weird.  No worries, this patch was very much stage 1 material anyway.

> 
> > > @@ -16771,9 +16722,10 @@ tsubst (tree t, tree args, tsubst_flags_t
> > > complain, tree in_decl)
> > >   ctx = TREE_VEC_ELT (ctx, 0);
> > > }
> > >   else
> > > -   ctx = tsubst_aggr_type (ctx, args,
> > > -   complain | tf_qualifying_scope,
> > > -   in_decl, /*entering_scope=*/1);
> > > +   {
> > > + ctx = tsubst_scope (ctx, args, complain, in_decl);
> 
> Why is this one tsubst_scope while the others are all plain tsubst?

Ah, just because the call to tsubst_aggr_type being replace passes
tf_qualifying_scope already, so we might as well use tsubst_scope
as shorthand.

> 
> Do we want a tsubst_entering_scope function?

Which is just shorthand for tsubst + adjust_type_for_entering_scope?
Sure, though I was wondering if we eventually might want to get rid of
the distinction between the primary template type A and the generic
instantiation A, and we could treat this as an incremental step
towards that (then we'd just eventually remove the
adjust_type_for_entering_scope calls and keep the tsubst calls).

> 
> > > + ctx = adjust_type_for_entering_scope (ctx);
> 
> 



Re: [PATCH 2/2] c++: remove lookup_template_class's entering_scope flag

2024-05-01 Thread Patrick Palka
On Fri, 2 Feb 2024, Patrick Palka wrote:

> Bootstrapped and regtested on x86_64-pc-linux, does this look like
> an improvement?  This is not a bugfix and barely related to the previous
> patch, but the previous patch's new use of entering_scope=true motivated
> me to submit this patch since it seems like a nice simplification.

Ping, now that stage 1 is open.

> 
> -- >8 --
> 
> lookup_template_class's entering_scope flag controls whether to prefer
> returning the primary template type A instead of the corresponding
> implicit instantiation A.  When we want to set this flag as part of
> substitution, we need to use tsubst_aggr_type which also takes the flag,
> but this separate entry point to substitution turned out to be subtly
> problematic because it doesn't reuse typedefs like tsubst does, which
> r13-4729-gbe124477b38a71 fixed in a way that respects the flag after the
> fact, by adjusting the entering_scope=false result of
> lookup_template_class as if entering_scope=true was passed.
> 
> But if that's possible then it means lookup_template_class's the
> entering_scope flag is not necessary after all -- we can just do the
> after-the-fact adjustment everywhere that we currently pass
> entering_scope=true to it and tsubst_aggr_type.
> 
> To that end, this patch replaces this flag with an adjustment function
> adjust_type_for_entering_scope, to be used whereever we currently need
> the entering_scope=true behavior.  This means we can also get rid of
> tsubst_aggr_type, since the only reason we needed this entry point
> was to be able to pass entering_scope=true to lookup_template_class.
> 
> gcc/cp/ChangeLog:
> 
>   * coroutines.cc (instantiate_coro_traits): Adjust call to
>   lookup_template_class.
>   (instantiate_coro_handle_for_promise_type): Likewise.
>   * cp-tree.h (adjust_type_for_entering_scope): Declare.
>   (lookup_template_class): Adjust declaration.
>   * decl.cc (make_typename_type): Adjust call to
>   lookup_template_class. Likewise.
>   (get_tuple_size): Likewise.
>   (get_tuple_element_type): Likewise.
>   * pt.cc (adjust_type_for_entering_scope): Define.
>   (lookup_template_class): Remove entering_scope parameter.
>   Replace tsubst_aggr_type call with tsubst followed by
>   adjust_type_for_entering_scope.
>   (tsubst_aggr_type): Remove.
>   (tsubst_aggr_type_1): Inline into tsubst.
>   (tsubst_function_decl): Replace tsubst_aggr_type call
>   with tsubst followed by adjust_type_for_entering_scope.
>   (tsubst_template_decl): Likewise.
>   (tsubst_decl): Likewise.
>   (tsubst) :
>   Inlined from tsubst_aggr_type_1.
>   : Adjust calls to
>   lookup_template_class.
>   : Replace tsubst_aggr_type call with
>   tsubst tsubst_scope followed by adjust_type_for_entering_scope.
>   : Replace tsubst_aggr_type
>   call with tsubst followed by adjust_type_for_entering_scope.
>   Increment processing_template_decl when substituting the
>   context.
>   (tsubst_baselink): Replace tsubst_aggr_type call with tsubst
>   followed by adjust_type_for_entering_scope.
>   (tsubst_expr) : Replace tsubst_aggr_type
>   call with tsubst followed by adjust_type_for_entering_scope.
>   : Likewise.
>   (instantiate_template): Likewise.
>   (resolve_typename_type): Adjust lookup_template_class call
>   and call adjust_type_for_entering_scope afterward.
>   (listify): Adjust lookup_template_class call.
>   (alias_ctad_tweaks): Likewise.
>   * semantics.cc (finish_template_type): Adjust lookup_template_class
>   call and maybe call adjust_type_for_entering_scope afterward.
> ---
>  gcc/cp/coroutines.cc |   4 +-
>  gcc/cp/cp-tree.h |   3 +-
>  gcc/cp/decl.cc   |   4 +-
>  gcc/cp/pt.cc | 212 +--
>  gcc/cp/semantics.cc  |   4 +-
>  5 files changed, 91 insertions(+), 136 deletions(-)
> 
> diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
> index 3194c911e8c..8dab173d5cb 100644
> --- a/gcc/cp/coroutines.cc
> +++ b/gcc/cp/coroutines.cc
> @@ -353,7 +353,7 @@ instantiate_coro_traits (tree fndecl, location_t kw)
>tree traits_class
>  = lookup_template_class (coro_traits_templ, targ,
>/*in_decl=*/NULL_TREE, /*context=*/NULL_TREE,
> -  /*entering scope=*/false, tf_warning_or_error);
> +  tf_warning_or_error);
>  
>if (traits_class == error_mark_node)
>  {
> @@ -400,7 +400,7 @@ instantiate_coro_handle_for_promise_type (location_t kw, 
> tree promise_type)
>  = lookup_template_class (coro_handle_identifier, targ,
>

Re: [PATCH 2/4] c++/modules: Track module purview for deferred instantiations [PR114630]

2024-05-01 Thread Patrick Palka
On Wed, 1 May 2024, Jason Merrill wrote:

> On 5/1/24 08:54, Patrick Palka wrote:
> > On Thu, 2 May 2024, Nathaniel Shead wrote:
> > 
> > > On Wed, May 01, 2024 at 10:11:20AM -0400, Patrick Palka wrote:
> > > > On Wed, 1 May 2024, Nathaniel Shead wrote:
> > > > 
> > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?
> > > > > 
> > > > > -- >8 --
> > > > > 
> > > > > When calling instantiate_pending_templates at end of parsing, any new
> > > > > functions that are instantiated from this point have their module
> > > > > purview set based on the current value of module_kind.
> > > > > 
> > > > > This is unideal, however, as the modules code will then treat these
> > > > > instantiations as reachable and cause large swathes of the GMF to be
> > > > > emitted into the module CMI, despite no code in the actual module
> > > > > purview referencing it.
> > > > > 
> > > > > This patch fixes this by also remembering the value of module_kind
> > > > > when
> > > > > the instantiation was deferred, and restoring it when doing this
> > > > > deferred instantiation.  That way newly instantiated declarations
> > > > > appropriately get a DECL_MODULE_PURVIEW_P appropriate for where the
> > > > > instantiation was required, meaning that GMF entities won't be counted
> > > > > as reachable unless referenced by an actually reachable entity.
> > > > > 
> > > > > Note that purviewness and attachment etc. is generally only determined
> > > > > by the base template: this is purely for determining whether a
> > > > > specialisation was declared in the module purview and hence whether it
> > > > > should be streamed out.  See the comment on
> > > > > 'set_instantiating_module'.
> > > > > 
> > > > >   PR c++/114630
> > > > >   PR c++/114795
> > > > > 
> > > > > gcc/cp/ChangeLog:
> > > > > 
> > > > >   * cp-tree.h (struct tinst_level): Add field for tracking
> > > > >   module_kind.
> > > > >   * pt.cc (push_tinst_level_loc): Cache module_kind in
> > > > > new_level.
> > > > >   (reopen_tinst_level): Restore module_kind from level.
> > > > >   (instantiate_pending_templates): Save and restore module_kind
> > > > > so
> > > > >   it isn't affected by reopen_tinst_level.
> > > > 
> > > > LGTM.  Another approach is to instantiate all so-far deferred
> > > > instantiations and vtables once we reach the start of the module
> > > > purview, but your approach is much cleaner.
> > > > 
> > > > Note that deferred instantiation can induce more deferred instantiation,
> > > > but your approach will do the right thing here (module_kind will be
> > > > inherited from the point of instantiation).
> > > > 
> > > > What if an instantiation is needed from both the GMF and the module
> > > > purview?  Then IIUC it'll be instantiated as if from the GMF, which
> > > > seems right to me.
> > > > 
> > > 
> > > Hm..., so I believe it'll be marked according to whichever instantiates
> > > it "first", so if e.g. deferred from GMF and then instantiated
> > > non-deferred from purview it'll be marked purview (and the deferred
> > > instantiation will be skipped as it's already instantiated).  This could
> > > mean it gets unnecessarily emitted if it only got instantiated because
> > > it got used in e.g. a non-inline function body, I suppose; but that's
> > > true in general actually, at the moment.
> > 
> > FWIW I think the most relevant situation where we need to instantiate
> > immediately and can't defer until EOF is during constexpr evaluation of
> > a variable initializer.  (We also immediately instantiate variable
> > template specializations, and function template specializations with
> > deduced return type, but in these cases we'd always instantiate from the
> > first use, i.e. from the GMF in this scenario.)
> > 
> > So I guess a testcase for this situation could be something like:
> > 
> >  module;
> >  template constexpr int f(T t) { return t; }
> >  template int f(int);
> > 
> >  export module foo;
> >  constexpr int w = f(0);
> >  // f ideally shouldn't be emitted in the CMI?
> 
> Does the explicit instantiation change that at all?  Either way it seams like
> f and f aren't decl-reachable from w if we determine that after constant
> evaluation.

Currently due to the bug in question we handle this as if the explicit
instantiation was performed from the module purview:

  module;
  template constexpr int f(T t) { return t; }

  export module foo;
  template int f(int);
  constexpr int w = f(0);

I think we do want to emit f in that case?



Re: [PATCH 2/4] c++/modules: Track module purview for deferred instantiations [PR114630]

2024-05-01 Thread Patrick Palka
On Thu, 2 May 2024, Nathaniel Shead wrote:

> On Wed, May 01, 2024 at 10:11:20AM -0400, Patrick Palka wrote:
> > On Wed, 1 May 2024, Nathaniel Shead wrote:
> > 
> > > Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?
> > > 
> > > -- >8 --
> > > 
> > > When calling instantiate_pending_templates at end of parsing, any new
> > > functions that are instantiated from this point have their module
> > > purview set based on the current value of module_kind.
> > > 
> > > This is unideal, however, as the modules code will then treat these
> > > instantiations as reachable and cause large swathes of the GMF to be
> > > emitted into the module CMI, despite no code in the actual module
> > > purview referencing it.
> > > 
> > > This patch fixes this by also remembering the value of module_kind when
> > > the instantiation was deferred, and restoring it when doing this
> > > deferred instantiation.  That way newly instantiated declarations
> > > appropriately get a DECL_MODULE_PURVIEW_P appropriate for where the
> > > instantiation was required, meaning that GMF entities won't be counted
> > > as reachable unless referenced by an actually reachable entity.
> > > 
> > > Note that purviewness and attachment etc. is generally only determined
> > > by the base template: this is purely for determining whether a
> > > specialisation was declared in the module purview and hence whether it
> > > should be streamed out.  See the comment on 'set_instantiating_module'.
> > > 
> > >   PR c++/114630
> > >   PR c++/114795
> > > 
> > > gcc/cp/ChangeLog:
> > > 
> > >   * cp-tree.h (struct tinst_level): Add field for tracking
> > >   module_kind.
> > >   * pt.cc (push_tinst_level_loc): Cache module_kind in new_level.
> > >   (reopen_tinst_level): Restore module_kind from level.
> > >   (instantiate_pending_templates): Save and restore module_kind so
> > >   it isn't affected by reopen_tinst_level.
> > 
> > LGTM.  Another approach is to instantiate all so-far deferred
> > instantiations and vtables once we reach the start of the module
> > purview, but your approach is much cleaner.
> > 
> > Note that deferred instantiation can induce more deferred instantiation,
> > but your approach will do the right thing here (module_kind will be
> > inherited from the point of instantiation).
> > 
> > What if an instantiation is needed from both the GMF and the module
> > purview?  Then IIUC it'll be instantiated as if from the GMF, which
> > seems right to me.
> > 
> 
> Hm..., so I believe it'll be marked according to whichever instantiates
> it "first", so if e.g. deferred from GMF and then instantiated
> non-deferred from purview it'll be marked purview (and the deferred
> instantiation will be skipped as it's already instantiated).  This could
> mean it gets unnecessarily emitted if it only got instantiated because
> it got used in e.g. a non-inline function body, I suppose; but that's
> true in general actually, at the moment.

FWIW I think the most relevant situation where we need to instantiate
immediately and can't defer until EOF is during constexpr evaluation of
a variable initializer.  (We also immediately instantiate variable
template specializations, and function template specializations with
deduced return type, but in these cases we'd always instantiate from the
first use, i.e. from the GMF in this scenario.)

So I guess a testcase for this situation could be something like:

module;
template constexpr int f(T t) { return t; }
template int f(int);

export module foo;
constexpr int w = f(0);
// f ideally shouldn't be emitted in the CMI?

> 
> Maybe then a better approach would be to instead always use the
> DECL_MODULE_PURVIEW_P of the instantiating template instead of the
> global 'module_purview_p' function in 'set_instantiating_module'?
> I think that should still make sure that instantiations are emitted
> when they need to be (because they'll be reachable from a declaration
> in the purview): I might try to experiment with something like this.

The approach of instantiating all so-far deferred instantiations/vtables
at the start of the module purview should handle this properly too.

> 
> > > 
> > > gcc/testsuite/ChangeLog:
> > > 
> > >   * g++.dg/modules/gmf-3.C: New test.
> > > 
> > > Signed-off-by: Nathaniel Shead 
> > > ---
> > >  gcc/cp/cp-tree.h |  3 +++
> > >  gcc/cp/pt.cc |  4 ++

Re: [PATCH 3/4] c++/modules: Also track module purview from deferred vtable instantiation [PR114630]

2024-05-01 Thread Patrick Palka
On Wed, 1 May 2024, Nathaniel Shead wrote:

> Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?

LGTM

> 
> -- >8 --
> 
> Similarly to in the previous commit, templated virtual functions are
> sometimes not instantiated until after parsing has completed.  This
> means that any new declarations they instantiate are incorrectly marked
> as being in the module purview, causing them to not be discarded from
> the GMF.
> 
>   PR c++/114630
>   PR c++/114795
> 
> gcc/cp/ChangeLog:
> 
>   * decl2.cc (mark_vtable_entries): Set module purview of deferred
>   instantiations from the function decl.
>   (c_parse_final_cleanups): Save and restore module_kind.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/modules/gmf-4.C: New test.
> 
> Signed-off-by: Nathaniel Shead 
> ---
>  gcc/cp/decl2.cc  | 11 +--
>  gcc/testsuite/g++.dg/modules/gmf-4.C | 27 +++
>  2 files changed, 36 insertions(+), 2 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/modules/gmf-4.C
> 
> diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc
> index 806a2a4bc69..0115a6b1cc9 100644
> --- a/gcc/cp/decl2.cc
> +++ b/gcc/cp/decl2.cc
> @@ -2210,6 +2210,11 @@ mark_vtable_entries (tree decl, vec 
> _vtables)
>   location, as we're called from c_parse_final_cleanups, which
>   takes care of that.  */
>input_location = DECL_SOURCE_LOCATION (fn);
> +  /* Similarly, any deferred instantiations should have the same
> +  module purview as this function.  */
> +  module_kind &= ~MK_PURVIEW;
> +  if (DECL_LANG_SPECIFIC (fn) && DECL_MODULE_PURVIEW_P (fn))
> + module_kind |= MK_PURVIEW;
>mark_used (fn);
>  }
>  }
> @@ -5085,6 +5090,7 @@ c_parse_final_cleanups (void)
>tree decl;
>  
>locus_at_end_of_parsing = input_location;
> +  unsigned module_kind_at_end_of_parsing = module_kind;
>/* We're done parsing.  */
>at_eof = 1;
>  
> @@ -5177,9 +5183,10 @@ c_parse_final_cleanups (void)
>   reconsider = true;
>   keyed_classes->unordered_remove (i);
> }
> -  /* The input_location may have been changed during marking of
> -  vtable entries.  */
> +  /* The input_location and module_kind may have been changed
> +  during marking of vtable entries.  */
>input_location = locus_at_end_of_parsing;
> +  module_kind = module_kind_at_end_of_parsing;
>  
>/* Write out needed type info variables.  We have to be careful
>looping through unemitted decls, because emit_tinfo_decl may
> diff --git a/gcc/testsuite/g++.dg/modules/gmf-4.C 
> b/gcc/testsuite/g++.dg/modules/gmf-4.C
> new file mode 100644
> index 000..c95bc782cea
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/modules/gmf-4.C
> @@ -0,0 +1,27 @@
> +// PR c++/114630
> +// { dg-additional-options "-fmodules-ts -Wno-global-module 
> -fdump-lang-module" }
> +// { dg-module-cmi M }
> +
> +// Deferred instantiation of GM virtual functions should not place
> +// newly discovered declarations in the module purview
> +
> +module;
> +
> +template 
> +void go() {
> +  extern T fn_decl();
> +}
> +
> +template 
> +struct S {
> +  virtual void f() {
> +go();
> +  }
> +};
> +
> +S s;
> +
> +export module M;
> +
> +// The whole GMF should be discarded here
> +// { dg-final { scan-lang-dump "Wrote 0 clusters" module } }
> -- 
> 2.43.2
> 
> 



Re: [PATCH 2/4] c++/modules: Track module purview for deferred instantiations [PR114630]

2024-05-01 Thread Patrick Palka
On Wed, 1 May 2024, Nathaniel Shead wrote:

> Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?
> 
> -- >8 --
> 
> When calling instantiate_pending_templates at end of parsing, any new
> functions that are instantiated from this point have their module
> purview set based on the current value of module_kind.
> 
> This is unideal, however, as the modules code will then treat these
> instantiations as reachable and cause large swathes of the GMF to be
> emitted into the module CMI, despite no code in the actual module
> purview referencing it.
> 
> This patch fixes this by also remembering the value of module_kind when
> the instantiation was deferred, and restoring it when doing this
> deferred instantiation.  That way newly instantiated declarations
> appropriately get a DECL_MODULE_PURVIEW_P appropriate for where the
> instantiation was required, meaning that GMF entities won't be counted
> as reachable unless referenced by an actually reachable entity.
> 
> Note that purviewness and attachment etc. is generally only determined
> by the base template: this is purely for determining whether a
> specialisation was declared in the module purview and hence whether it
> should be streamed out.  See the comment on 'set_instantiating_module'.
> 
>   PR c++/114630
>   PR c++/114795
> 
> gcc/cp/ChangeLog:
> 
>   * cp-tree.h (struct tinst_level): Add field for tracking
>   module_kind.
>   * pt.cc (push_tinst_level_loc): Cache module_kind in new_level.
>   (reopen_tinst_level): Restore module_kind from level.
>   (instantiate_pending_templates): Save and restore module_kind so
>   it isn't affected by reopen_tinst_level.

LGTM.  Another approach is to instantiate all so-far deferred
instantiations and vtables once we reach the start of the module
purview, but your approach is much cleaner.

Note that deferred instantiation can induce more deferred instantiation,
but your approach will do the right thing here (module_kind will be
inherited from the point of instantiation).

What if an instantiation is needed from both the GMF and the module
purview?  Then IIUC it'll be instantiated as if from the GMF, which
seems right to me.

> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/modules/gmf-3.C: New test.
> 
> Signed-off-by: Nathaniel Shead 
> ---
>  gcc/cp/cp-tree.h |  3 +++
>  gcc/cp/pt.cc |  4 
>  gcc/testsuite/g++.dg/modules/gmf-3.C | 13 +
>  3 files changed, 20 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/modules/gmf-3.C
> 
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 1938ada0268..0e619120ccc 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -6626,6 +6626,9 @@ struct GTY((chain_next ("%h.next"))) tinst_level {
>/* The location where the template is instantiated.  */
>location_t locus;
>  
> +  /* The module kind where the template is instantiated. */
> +  unsigned module_kind;
> +
>/* errorcount + sorrycount when we pushed this level.  */
>unsigned short errors;
>  
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 1c3eef60c06..401aa92bc3e 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -11277,6 +11277,7 @@ push_tinst_level_loc (tree tldcl, tree targs, 
> location_t loc)
>new_level->tldcl = tldcl;
>new_level->targs = targs;
>new_level->locus = loc;
> +  new_level->module_kind = module_kind;
>new_level->errors = errorcount + sorrycount;
>new_level->next = NULL;
>new_level->refcount = 0;
> @@ -11345,6 +11346,7 @@ reopen_tinst_level (struct tinst_level *level)
>for (t = level; t; t = t->next)
>  ++tinst_depth;
>  
> +  module_kind = level->module_kind;
>set_refcount_ptr (current_tinst_level, level);
>pop_tinst_level ();
>if (current_tinst_level)
> @@ -27442,6 +27444,7 @@ instantiate_pending_templates (int retries)
>  {
>int reconsider;
>location_t saved_loc = input_location;
> +  unsigned saved_module_kind = module_kind;
>  
>/* Instantiating templates may trigger vtable generation.  This in turn
>   may require further template instantiations.  We place a limit here
> @@ -27532,6 +27535,7 @@ instantiate_pending_templates (int retries)
>while (reconsider);
>  
>input_location = saved_loc;
> +  module_kind = saved_module_kind;
>  }
>  
>  /* Substitute ARGVEC into T, which is a list of initializers for
> diff --git a/gcc/testsuite/g++.dg/modules/gmf-3.C 
> b/gcc/testsuite/g++.dg/modules/gmf-3.C
> new file mode 100644
> index 000..e52ae904ea9
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/modules/gmf-3.C
> @@ -0,0 +1,13 @@
> +// PR c++/114630
> +// { dg-additional-options "-fmodules-ts -Wno-global-module 
> -fdump-lang-module" }
> +// { dg-module-cmi M }
> +
> +module;
> +template  struct allocator {
> +  allocator() {}
> +};
> +template class allocator;
> +export module M;
> +
> +// The whole GMF should be discarded here
> +// { dg-final { scan-lang-dump "Wrote 0 clusters" module 

Re: [PATCH] c++/modules: Fix dangling pointer with imported_temploid_friends

2024-05-01 Thread Patrick Palka


On Wed, 1 May 2024, Nathaniel Shead wrote:

> Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk (and
> later 14.2)?  I don't think making it a GTY root is necessary but I felt
> perhaps better to be safe than sorry.
> 
> Potentially another approach would be to use DECL_UID instead like how
> entity_map does; would that be preferable?
> 
> -- >8 --
> 
> I got notified by Linaro CI and by checking testresults that there seems
> to be some occasional failures in tpl-friend-4_b.C on some architectures
> and standards modes since r15-59-gb5f6a56940e708.  I haven't been able
> to reproduce but looking at the backtrace I suspect the issue is that
> we're adding to the 'imported_temploid_friend' map a decl that is
> ultimately discarded, which then has its address reused by a later decl
> causing a failure in the assert in 'set_originating_module'.
> 
> This patch attempts to fix the issue in two ways: by ensuring that we
> only store the decl if we know it's a new decl (and hence won't be
> discarded), and by making the imported_temploid_friends map a GTY root
> so that even if the decl does get discarded later the address isn't
> reused.
> 
> gcc/cp/ChangeLog:
> 
>   * module.cc (imported_temploid_friends): Mark GTY, and...
>   (init_modules): ...allocate from GGC.
>   (trees_in::decl_value): Only write to imported_temploid_friends
>   for new decls.
> 
> Signed-off-by: Nathaniel Shead 
> ---
>  gcc/cp/module.cc | 7 ---
>  1 file changed, 4 insertions(+), 3 deletions(-)
> 
> diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> index 5b8ff5bc483..37d38bb9654 100644
> --- a/gcc/cp/module.cc
> +++ b/gcc/cp/module.cc
> @@ -2731,7 +2731,7 @@ static keyed_map_t *keyed_table;
> need to be attached to the same module as the temploid.  This maps
> these decls to the temploid they are instantiated them, as there is
> no other easy way to get this information.  */
> -static hash_map *imported_temploid_friends;
> +static GTY(()) hash_map *imported_temploid_friends;
>  
>  //
>  /* Tree streaming.   The tree streaming is very specific to the tree
> @@ -8327,7 +8327,8 @@ trees_in::decl_value ()
>if (TREE_CODE (inner) == FUNCTION_DECL
>|| TREE_CODE (inner) == TYPE_DECL)
>  if (tree owner = tree_node ())
> -  imported_temploid_friends->put (decl, owner);
> +  if (is_new)
> + imported_temploid_friends->put (decl, owner);

Hmm, I'm not seeing this code path getting reached for tpl-friend-4_b.C.
It seems we're instead adding to imported_temploid_friends from
propagate_defining_module, during tsubst_friend_function.

What seems to be happening is that we we first tsubst_friend_function
'foo' from TPL, and then we tsubst_friend_function 'foo' from DEF,
which ends up calling duplicate_decls, which ggc_frees this 'foo'
redeclaration that is still present in the imported_temploid_friends map.

So I don't think marking imported_temploid_friends as a GC root would
help with this situation.  If we want to keep imported_temploid_friends
as a tree -> tree map, I think we just need to ensure that a decl
is removed from the map upon getting ggc_free'd from e.g.  duplicate_decls.

But it seems simpler to use DECL_UID as the key instead, since those
never get reused even after the decl gets ggc_free'd IIUC.

>  
>/* Regular typedefs will have a NULL TREE_TYPE at this point.  */
>unsigned tdef_flags = 0;
> @@ -20523,7 +20524,7 @@ init_modules (cpp_reader *reader)
>entity_map = new entity_map_t (EXPERIMENT (1, 400));
>vec_safe_reserve (entity_ary, EXPERIMENT (1, 400));
>imported_temploid_friends
> - = new hash_map (EXPERIMENT (1, 400));
> + = hash_map::create_ggc (EXPERIMENT (1, 400));
>  }
>  
>  #if CHECKING_P
> -- 
> 2.43.2
> 
> 



[PATCH] c++: ICE with templated sizeof(E1) / sizeof(E2) [PR114888]

2024-04-29 Thread Patrick Palka
Lightly tested on x86_64-pc-linux-gnu so far, does this look OK for
trunk/14.1 after bootstrap+regtest finishes?

-- >8 --

We're missing a dependence check for the second operand in the
sizeof / sizeof handling.

PR c++/114888

gcc/cp/ChangeLog:

* typeck.cc (cp_build_binary_op) : Add missing
dependence check for the second sizeof operand.

gcc/testsuite/ChangeLog:

* g++.dg/template/sizeof19.C: New test.
---
 gcc/cp/typeck.cc | 1 +
 gcc/testsuite/g++.dg/template/sizeof19.C | 8 
 2 files changed, 9 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/template/sizeof19.C

diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index e5a52dc2b39..a25f8622651 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -5501,6 +5501,7 @@ cp_build_binary_op (const op_location_t ,
  if (!TYPE_P (type1))
type1 = TREE_TYPE (type1);
  if (type0
+ && type1
  && INDIRECT_TYPE_P (type0)
  && same_type_p (TREE_TYPE (type0), type1))
{
diff --git a/gcc/testsuite/g++.dg/template/sizeof19.C 
b/gcc/testsuite/g++.dg/template/sizeof19.C
new file mode 100644
index 000..a1467995a9b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/sizeof19.C
@@ -0,0 +1,8 @@
+// PR c++/114888
+
+template
+struct A {
+  struct B {} *b;
+  static const int c = sizeof (b) / sizeof (b[0]);
+};
+const int d = A::c;
-- 
2.45.0.rc1



[PATCH] c++/modules: imported spec befriending class tmpl [PR114889]

2024-04-29 Thread Patrick Palka
Tested on x86_64-pc-linux-gnu, does this look OK for trunk and perhaps
14 (I guess after 14.1 is released)?

-- >8 --

We need to look through TEMPLATE_DECL like make_friend_class does when
adding to CLASSTYPE_BEFRIENDING_CLASSES.

Otherwise in the below testcase we won't add _Hashtable to
CLASSTYPE_BEFRIENDING_CLASSES of _Map_base when installing the definition
of the former which leads to access control issues.

PR c++/114889

gcc/cp/ChangeLog:

* module.cc (trees_in::read_class_def): Look through
TEMPLATE_DECL when adding to CLASSTYPE_BEFRIENDING_CLASSES.

gcc/testsuite/ChangeLog:

* g++.dg/modules/friend-8_a.H: New test.
* g++.dg/modules/friend-8_b.C: New test.
---
 gcc/cp/module.cc  |  2 ++
 gcc/testsuite/g++.dg/modules/friend-8_a.H | 23 +++
 gcc/testsuite/g++.dg/modules/friend-8_b.C |  9 +
 3 files changed, 34 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/modules/friend-8_a.H
 create mode 100644 gcc/testsuite/g++.dg/modules/friend-8_b.C

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 7e654305f0a..3b2ba40c92b 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -12518,6 +12518,8 @@ trees_in::read_class_def (tree defn, tree 
maybe_template)
  for (; friend_classes; friend_classes = TREE_CHAIN (friend_classes))
{
  tree f = TREE_VALUE (friend_classes);
+ if (TREE_CODE (f) == TEMPLATE_DECL)
+   f = TREE_TYPE (f);
 
  if (CLASS_TYPE_P (f))
{
diff --git a/gcc/testsuite/g++.dg/modules/friend-8_a.H 
b/gcc/testsuite/g++.dg/modules/friend-8_a.H
new file mode 100644
index 000..b07ea25adfb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/friend-8_a.H
@@ -0,0 +1,23 @@
+// PR c++/114889
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+template
+struct _Hashtable;
+
+template
+struct _Map_base {
+  void f() {
+_Hashtable<_Key, _Val> __h;
+__h._M_hash_code(0);
+  }
+};
+
+template
+struct _Hashtable {
+  template friend struct _Map_base;
+protected:
+  void _M_hash_code(int);
+};
+
+inline _Hashtable m;
diff --git a/gcc/testsuite/g++.dg/modules/friend-8_b.C 
b/gcc/testsuite/g++.dg/modules/friend-8_b.C
new file mode 100644
index 000..b04280bc91a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/friend-8_b.C
@@ -0,0 +1,9 @@
+// PR c++/114889
+// { dg-additional-options "-fmodules-ts" }
+
+import "friend-8_a.H";
+
+int main() {
+  _Map_base m;
+  m.f();
+}
-- 
2.45.0.rc1



Re: [PATCH] c++: fix source printing for "required from here" message

2024-04-26 Thread Patrick Palka
On Thu, 25 Apr 2024, David Malcolm wrote:

> On Wed, 2024-04-24 at 17:05 -0400, Patrick Palka wrote:
> > On Wed, 24 Apr 2024, Jason Merrill wrote:
> > 
> > > On 4/24/24 13:22, Patrick Palka wrote:
> > > > Tested on x86_64-pc-linux-gnu, full bootstrap+regtest in
> > > > progress,
> > > > does this look OK if successful?
> > > > 
> > > > -- >8 --
> > > > 
> > > > It seems the diagnostic machinery's source line printing respects
> > > > the pretty printer prefix, but this is undesirable for the call
> > > > to
> > > > diagnostic_show_locus in print_instantiation_partial_context_line
> > > > added in r14-4388-g1c45319b66edc9 since the prefix may have been
> > > > set when issuing an earlier, unrelated diagnostic and we just
> > > > want
> > > > to print an unprefixed source line.
> > > > 
> > > > This patch naively fixes this by clearing the prefix before
> > > > calling
> > > > diagnostic_show_locus.
> > > > 
> > > > Before this patch, for error60a.C below we'd print
> > > > 
> > > > gcc/testsuite/g++.dg/template/error60a.C: In function ‘void
> > > > usage()’:
> > > > gcc/testsuite/g++.dg/template/error60a.C:24:3: error:
> > > > ‘unrelated_error’ was
> > > > not declared in this scope
> > > >     24 |   unrelated_error; // { dg-error "not declared" }
> > > >    |   ^~~
> > > > gcc/testsuite/g++.dg/template/error60a.C: In instantiation of
> > > > ‘void
> > > > test(Foo) [with Foo = int]’:
> > > > gcc/testsuite/g++.dg/template/error60a.C:25:13:   required from
> > > > here
> > > > gcc/testsuite/g++.dg/template/error60a.C:24:3: error:    25 |  
> > > > test
> > > > (42); // { dg-message " required from here" }
> > > > gcc/testsuite/g++.dg/template/error60a.C:24:3: error:   |
> > > > ~~^~~~
> > > > gcc/testsuite/g++.dg/template/error60a.C:19:24: error: invalid
> > > > conversion
> > > > from ‘int’ to ‘int*’ [-fpermissive]
> > > >     19 |   my_pointer ptr (val); // { dg-error "invalid
> > > > conversion from
> > > > 'int' to 'int\\*'" }
> > > >    |    ^~~
> > > >    |    |
> > > >    |    int
> > > > gcc/testsuite/g++.dg/template/error60a.C:9:20: note:  
> > > > initializing argument
> > > > 1 of ‘my_pointer::my_pointer(Foo*) [with Foo = int]’
> > > >  9 |   my_pointer (Foo *ptr) // { dg-message " initializing
> > > > argument 1"
> > > > }
> > > >    |   ~^~~
> > > > 
> > > > and afterward we print
> > > > 
> > > > gcc/testsuite/g++.dg/template/error60a.C: In function ‘void
> > > > usage()’:
> > > > gcc/testsuite/g++.dg/template/error60a.C:24:3: error:
> > > > ‘unrelated_error’ was
> > > > not declared in this scope
> > > >     24 |   unrelated_error; // { dg-error "not declared" }
> > > >    |   ^~~
> > > > gcc/testsuite/g++.dg/template/error60a.C: In instantiation of
> > > > ‘void
> > > > test(Foo) [with Foo = int]’:
> > > > gcc/testsuite/g++.dg/template/error60a.C:25:13:   required from
> > > > here
> > > >     25 |   test (42); // { dg-message " required from here"
> > > > }
> > > >    |   ~~^~~~
> > > > gcc/testsuite/g++.dg/template/error60a.C:19:24: error: invalid
> > > > conversion
> > > > from ‘int’ to ‘int*’ [-fpermissive]
> > > >     19 |   my_pointer ptr (val); // { dg-error "invalid
> > > > conversion from
> > > > 'int' to 'int\\*'" }
> > > >    |    ^~~
> > > >    |    |
> > > >    |    int
> > > > gcc/testsuite/g++.dg/template/error60a.C:9:20: note:  
> > > > initializing argument
> > > > 1 of ‘my_pointer::my_pointer(Foo*) [with Foo = int]’
> > > >  9 |   my_pointer (Foo *ptr) // { dg-message " initializing
> > > > argument 1"
> > > > }
> > > >    |   ~^~~
> > > > 
> > > > gcc/cp/C

Re: [PATCH] c++: fix source printing for "required from here" message

2024-04-24 Thread Patrick Palka
On Wed, 24 Apr 2024, Jason Merrill wrote:

> On 4/24/24 13:22, Patrick Palka wrote:
> > Tested on x86_64-pc-linux-gnu, full bootstrap+regtest in progress,
> > does this look OK if successful?
> > 
> > -- >8 --
> > 
> > It seems the diagnostic machinery's source line printing respects
> > the pretty printer prefix, but this is undesirable for the call to
> > diagnostic_show_locus in print_instantiation_partial_context_line
> > added in r14-4388-g1c45319b66edc9 since the prefix may have been
> > set when issuing an earlier, unrelated diagnostic and we just want
> > to print an unprefixed source line.
> > 
> > This patch naively fixes this by clearing the prefix before calling
> > diagnostic_show_locus.
> > 
> > Before this patch, for error60a.C below we'd print
> > 
> > gcc/testsuite/g++.dg/template/error60a.C: In function ‘void usage()’:
> > gcc/testsuite/g++.dg/template/error60a.C:24:3: error: ‘unrelated_error’ was
> > not declared in this scope
> > 24 |   unrelated_error; // { dg-error "not declared" }
> >|   ^~~
> > gcc/testsuite/g++.dg/template/error60a.C: In instantiation of ‘void
> > test(Foo) [with Foo = int]’:
> > gcc/testsuite/g++.dg/template/error60a.C:25:13:   required from here
> > gcc/testsuite/g++.dg/template/error60a.C:24:3: error:25 |   test
> > (42); // { dg-message " required from here" }
> > gcc/testsuite/g++.dg/template/error60a.C:24:3: error:   |
> > ~~^~~~
> > gcc/testsuite/g++.dg/template/error60a.C:19:24: error: invalid conversion
> > from ‘int’ to ‘int*’ [-fpermissive]
> > 19 |   my_pointer ptr (val); // { dg-error "invalid conversion from
> > 'int' to 'int\\*'" }
> >|^~~
> >||
> >|int
> > gcc/testsuite/g++.dg/template/error60a.C:9:20: note:   initializing argument
> > 1 of ‘my_pointer::my_pointer(Foo*) [with Foo = int]’
> >  9 |   my_pointer (Foo *ptr) // { dg-message " initializing argument 1"
> > }
> >|   ~^~~
> > 
> > and afterward we print
> > 
> > gcc/testsuite/g++.dg/template/error60a.C: In function ‘void usage()’:
> > gcc/testsuite/g++.dg/template/error60a.C:24:3: error: ‘unrelated_error’ was
> > not declared in this scope
> > 24 |   unrelated_error; // { dg-error "not declared" }
> >|   ^~~
> > gcc/testsuite/g++.dg/template/error60a.C: In instantiation of ‘void
> > test(Foo) [with Foo = int]’:
> > gcc/testsuite/g++.dg/template/error60a.C:25:13:   required from here
> > 25 |   test (42); // { dg-message " required from here" }
> >|   ~~^~~~
> > gcc/testsuite/g++.dg/template/error60a.C:19:24: error: invalid conversion
> > from ‘int’ to ‘int*’ [-fpermissive]
> > 19 |   my_pointer ptr (val); // { dg-error "invalid conversion from
> > 'int' to 'int\\*'" }
> >|^~~
> >||
> >|int
> > gcc/testsuite/g++.dg/template/error60a.C:9:20: note:   initializing argument
> > 1 of ‘my_pointer::my_pointer(Foo*) [with Foo = int]’
> >  9 |   my_pointer (Foo *ptr) // { dg-message " initializing argument 1"
> > }
> >|   ~^~~
> > 
> > gcc/cp/ChangeLog:
> > 
> > * error.cc (print_instantiation_partial_context_line): Clear
> > context->printer->prefix around the call to diagnostic_show_locus.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/concepts/diagnostic2.C: Expect source line printed
> > for the required from here message.
> > * g++.dg/template/error60a.C: New test.
> > ---
> >   gcc/cp/error.cc |  2 +
> >   gcc/testsuite/g++.dg/concepts/diagnostic2.C |  6 ++-
> >   gcc/testsuite/g++.dg/template/error60a.C| 46 +
> >   3 files changed, 53 insertions(+), 1 deletion(-)
> >   create mode 100644 gcc/testsuite/g++.dg/template/error60a.C
> > 
> > diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
> > index 7074845154e..a7067d4d2ed 100644
> > --- a/gcc/cp/error.cc
> > +++ b/gcc/cp/error.cc
> > @@ -3793,7 +3793,9 @@ print_instantiation_partial_context_line
> > (diagnostic_context *context,
> >: _("required from here\n"));
> >   }
> > gcc_rich_location rich_loc (loc);
> > +  char *saved_prefix = pp_take_prefix (c

[PATCH] c++: fix source printing for "required from here" message

2024-04-24 Thread Patrick Palka
Tested on x86_64-pc-linux-gnu, full bootstrap+regtest in progress,
does this look OK if successful?

-- >8 --

It seems the diagnostic machinery's source line printing respects
the pretty printer prefix, but this is undesirable for the call to
diagnostic_show_locus in print_instantiation_partial_context_line
added in r14-4388-g1c45319b66edc9 since the prefix may have been
set when issuing an earlier, unrelated diagnostic and we just want
to print an unprefixed source line.

This patch naively fixes this by clearing the prefix before calling
diagnostic_show_locus.

Before this patch, for error60a.C below we'd print

gcc/testsuite/g++.dg/template/error60a.C: In function ‘void usage()’:
gcc/testsuite/g++.dg/template/error60a.C:24:3: error: ‘unrelated_error’ was not 
declared in this scope
   24 |   unrelated_error; // { dg-error "not declared" }
  |   ^~~
gcc/testsuite/g++.dg/template/error60a.C: In instantiation of ‘void test(Foo) 
[with Foo = int]’:
gcc/testsuite/g++.dg/template/error60a.C:25:13:   required from here
gcc/testsuite/g++.dg/template/error60a.C:24:3: error:25 |   test (42); 
// { dg-message " required from here" }
gcc/testsuite/g++.dg/template/error60a.C:24:3: error:   |   ~~^~~~
gcc/testsuite/g++.dg/template/error60a.C:19:24: error: invalid conversion from 
‘int’ to ‘int*’ [-fpermissive]
   19 |   my_pointer ptr (val); // { dg-error "invalid conversion from 
'int' to 'int\\*'" }
  |^~~
  ||
  |int
gcc/testsuite/g++.dg/template/error60a.C:9:20: note:   initializing argument 1 
of ‘my_pointer::my_pointer(Foo*) [with Foo = int]’
9 |   my_pointer (Foo *ptr) // { dg-message " initializing argument 1" }
  |   ~^~~

and afterward we print

gcc/testsuite/g++.dg/template/error60a.C: In function ‘void usage()’:
gcc/testsuite/g++.dg/template/error60a.C:24:3: error: ‘unrelated_error’ was not 
declared in this scope
   24 |   unrelated_error; // { dg-error "not declared" }
  |   ^~~
gcc/testsuite/g++.dg/template/error60a.C: In instantiation of ‘void test(Foo) 
[with Foo = int]’:
gcc/testsuite/g++.dg/template/error60a.C:25:13:   required from here
   25 |   test (42); // { dg-message " required from here" }
  |   ~~^~~~
gcc/testsuite/g++.dg/template/error60a.C:19:24: error: invalid conversion from 
‘int’ to ‘int*’ [-fpermissive]
   19 |   my_pointer ptr (val); // { dg-error "invalid conversion from 
'int' to 'int\\*'" }
  |^~~
  ||
  |int
gcc/testsuite/g++.dg/template/error60a.C:9:20: note:   initializing argument 1 
of ‘my_pointer::my_pointer(Foo*) [with Foo = int]’
9 |   my_pointer (Foo *ptr) // { dg-message " initializing argument 1" }
  |   ~^~~

gcc/cp/ChangeLog:

* error.cc (print_instantiation_partial_context_line): Clear
context->printer->prefix around the call to diagnostic_show_locus.

gcc/testsuite/ChangeLog:

* g++.dg/concepts/diagnostic2.C: Expect source line printed
for the required from here message.
* g++.dg/template/error60a.C: New test.
---
 gcc/cp/error.cc |  2 +
 gcc/testsuite/g++.dg/concepts/diagnostic2.C |  6 ++-
 gcc/testsuite/g++.dg/template/error60a.C| 46 +
 3 files changed, 53 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/template/error60a.C

diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
index 7074845154e..a7067d4d2ed 100644
--- a/gcc/cp/error.cc
+++ b/gcc/cp/error.cc
@@ -3793,7 +3793,9 @@ print_instantiation_partial_context_line 
(diagnostic_context *context,
   : _("required from here\n"));
 }
   gcc_rich_location rich_loc (loc);
+  char *saved_prefix = pp_take_prefix (context->printer);
   diagnostic_show_locus (context, _loc, DK_NOTE);
+  context->printer->prefix = saved_prefix;
 }
 
 /* Same as print_instantiation_full_context but less verbose.  */
diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic2.C 
b/gcc/testsuite/g++.dg/concepts/diagnostic2.C
index 6550ed6b3bd..d6f5872de2c 100644
--- a/gcc/testsuite/g++.dg/concepts/diagnostic2.C
+++ b/gcc/testsuite/g++.dg/concepts/diagnostic2.C
@@ -23,7 +23,11 @@ void
 baz()
 {
   bar(); // { dg-error "no match" }
-/* { dg-begin-multiline-output "" }
+/* { dg-begin-multiline-output "for no match error" }
+   bar();
+   ^~
+   { dg-end-multiline-output "" } */
+/* { dg-begin-multiline-output "for required from here message" }
bar();
^~
{ dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/g++.dg/template/error60a.C 
b/gcc/testsuite/g++.dg/template/error60a.C
new file mode 100644
index 000..7c2f8188d16
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/error60a.C
@@ -0,0 +1,46 @@
+// Like error60.C but first issues an unrelated error that
+// causes the pretty printer prefix to get set, 

Re: [PATCH] c++: print source code in print_instantiation_partial_context_line

2024-04-24 Thread Patrick Palka
On Wed, 24 Apr 2024, Patrick Palka wrote:

> On Tue, 9 Apr 2024, Patrick Palka wrote:
> 
> > On Thu, 19 Oct 2023, Patrick Palka wrote:
> > 
> > > On Tue, 3 Oct 2023, David Malcolm wrote:
> > > 
> > > > As mentioned in my Cauldron talk, this patch adds a call to
> > > > diagnostic_show_locus to the "required from here" messages
> > > > in print_instantiation_partial_context_line, so that e.g., rather
> > > > than the rather mystifying:
> > > > 
> > > > In file included from 
> > > > ../x86_64-pc-linux-gnu/libstdc++-v3/include/memory:78,
> > > >  from ../../src/demo-1.C:1:
> > > > ../x86_64-pc-linux-gnu/libstdc++-v3/include/bits/unique_ptr.h: In 
> > > > instantiation of ‘std::__detail::__unique_ptr_t<_Tp> 
> > > > std::make_unique(_Args&& ...) [with _Tp = bar; _Args = {}; 
> > > > __detail::__unique_ptr_t<_Tp> = __detail::__unique_ptr_t]’:
> > > > ../../src/demo-1.C:15:32:   required from here
> > > > ../x86_64-pc-linux-gnu/libstdc++-v3/include/bits/unique_ptr.h:1066:30: 
> > > > error: no matching function for call to ‘bar::bar()’
> > > >  1066 | { return unique_ptr<_Tp>(new 
> > > > _Tp(std::forward<_Args>(__args)...)); }
> > > >   |  
> > > > ^~~
> > > > ../../src/demo-1.C:10:3: note: candidate: ‘bar::bar(int)’
> > > >10 |   bar (int);
> > > >   |   ^~~
> > > > ../../src/demo-1.C:10:3: note:   candidate expects 1 argument, 0 
> > > > provided
> > > > ../../src/demo-1.C:7:7: note: candidate: ‘constexpr bar::bar(const 
> > > > bar&)’
> > > > 7 | class bar : public foo
> > > >   |   ^~~
> > > > ../../src/demo-1.C:7:7: note:   candidate expects 1 argument, 0 provided
> > > > ../../src/demo-1.C:7:7: note: candidate: ‘constexpr bar::bar(bar&&)’
> > > > ../../src/demo-1.C:7:7: note:   candidate expects 1 argument, 0 provided
> > > > 
> > > > we emit:
> > > > 
> > > > In file included from 
> > > > ../x86_64-pc-linux-gnu/libstdc++-v3/include/memory:78,
> > > >  from ../../src/demo-1.C:1:
> > > > ../x86_64-pc-linux-gnu/libstdc++-v3/include/bits/unique_ptr.h: In 
> > > > instantiation of ‘std::__detail::__unique_ptr_t<_Tp> 
> > > > std::make_unique(_Args&& ...) [with _Tp = bar; _Args = {}; 
> > > > __detail::__unique_ptr_t<_Tp> = __detail::__unique_ptr_t]’:
> > > > ../../src/demo-1.C:15:32:   required from here
> > > >15 |   return std::make_unique ();
> > > >   |  ~~^~
> > > > ../x86_64-pc-linux-gnu/libstdc++-v3/include/bits/unique_ptr.h:1066:30: 
> > > > error: no matching function for call to ‘bar::bar()’
> > > >  1066 | { return unique_ptr<_Tp>(new 
> > > > _Tp(std::forward<_Args>(__args)...)); }
> > > >   |  
> > > > ^~~
> > > > ../../src/demo-1.C:10:3: note: candidate: ‘bar::bar(int)’
> > > >10 |   bar (int);
> > > >   |   ^~~
> > > > ../../src/demo-1.C:10:3: note:   candidate expects 1 argument, 0 
> > > > provided
> > > > ../../src/demo-1.C:7:7: note: candidate: ‘constexpr bar::bar(const 
> > > > bar&)’
> > > > 7 | class bar : public foo
> > > >   |   ^~~
> > > > ../../src/demo-1.C:7:7: note:   candidate expects 1 argument, 0 provided
> > > > ../../src/demo-1.C:7:7: note: candidate: ‘constexpr bar::bar(bar&&)’
> > > > ../../src/demo-1.C:7:7: note:   candidate expects 1 argument, 0 provided
> > > > 
> > > > which shows the code that's leading to the error (the bad call to
> > > > std::make_unique).
> > > 
> > > This is great!  I noticed however that the source code gets printed in a
> > > surprising way in some contexts.  Consider:
> > > 
> > > template void f(typename T::type);
> > > 
> > > int main() {
> > >   f(0);
> > > }
> > > 
> > > For this testcase we emit:
> > > 
> > > testcase.C: In function ‘int main()’:
> > > testcase.C:4:9: error: no matching function for call to ‘f(int)’
> > > 4 |   f(0);
> > >   

Re: [PATCH] c++: print source code in print_instantiation_partial_context_line

2024-04-24 Thread Patrick Palka
On Tue, 9 Apr 2024, Patrick Palka wrote:

> On Thu, 19 Oct 2023, Patrick Palka wrote:
> 
> > On Tue, 3 Oct 2023, David Malcolm wrote:
> > 
> > > As mentioned in my Cauldron talk, this patch adds a call to
> > > diagnostic_show_locus to the "required from here" messages
> > > in print_instantiation_partial_context_line, so that e.g., rather
> > > than the rather mystifying:
> > > 
> > > In file included from 
> > > ../x86_64-pc-linux-gnu/libstdc++-v3/include/memory:78,
> > >  from ../../src/demo-1.C:1:
> > > ../x86_64-pc-linux-gnu/libstdc++-v3/include/bits/unique_ptr.h: In 
> > > instantiation of ‘std::__detail::__unique_ptr_t<_Tp> 
> > > std::make_unique(_Args&& ...) [with _Tp = bar; _Args = {}; 
> > > __detail::__unique_ptr_t<_Tp> = __detail::__unique_ptr_t]’:
> > > ../../src/demo-1.C:15:32:   required from here
> > > ../x86_64-pc-linux-gnu/libstdc++-v3/include/bits/unique_ptr.h:1066:30: 
> > > error: no matching function for call to ‘bar::bar()’
> > >  1066 | { return unique_ptr<_Tp>(new 
> > > _Tp(std::forward<_Args>(__args)...)); }
> > >   |  
> > > ^~~
> > > ../../src/demo-1.C:10:3: note: candidate: ‘bar::bar(int)’
> > >10 |   bar (int);
> > >   |   ^~~
> > > ../../src/demo-1.C:10:3: note:   candidate expects 1 argument, 0 provided
> > > ../../src/demo-1.C:7:7: note: candidate: ‘constexpr bar::bar(const bar&)’
> > > 7 | class bar : public foo
> > >   |   ^~~
> > > ../../src/demo-1.C:7:7: note:   candidate expects 1 argument, 0 provided
> > > ../../src/demo-1.C:7:7: note: candidate: ‘constexpr bar::bar(bar&&)’
> > > ../../src/demo-1.C:7:7: note:   candidate expects 1 argument, 0 provided
> > > 
> > > we emit:
> > > 
> > > In file included from 
> > > ../x86_64-pc-linux-gnu/libstdc++-v3/include/memory:78,
> > >  from ../../src/demo-1.C:1:
> > > ../x86_64-pc-linux-gnu/libstdc++-v3/include/bits/unique_ptr.h: In 
> > > instantiation of ‘std::__detail::__unique_ptr_t<_Tp> 
> > > std::make_unique(_Args&& ...) [with _Tp = bar; _Args = {}; 
> > > __detail::__unique_ptr_t<_Tp> = __detail::__unique_ptr_t]’:
> > > ../../src/demo-1.C:15:32:   required from here
> > >15 |   return std::make_unique ();
> > >   |  ~~^~
> > > ../x86_64-pc-linux-gnu/libstdc++-v3/include/bits/unique_ptr.h:1066:30: 
> > > error: no matching function for call to ‘bar::bar()’
> > >  1066 | { return unique_ptr<_Tp>(new 
> > > _Tp(std::forward<_Args>(__args)...)); }
> > >   |  
> > > ^~~
> > > ../../src/demo-1.C:10:3: note: candidate: ‘bar::bar(int)’
> > >10 |   bar (int);
> > >   |   ^~~
> > > ../../src/demo-1.C:10:3: note:   candidate expects 1 argument, 0 provided
> > > ../../src/demo-1.C:7:7: note: candidate: ‘constexpr bar::bar(const bar&)’
> > > 7 | class bar : public foo
> > >   |   ^~~
> > > ../../src/demo-1.C:7:7: note:   candidate expects 1 argument, 0 provided
> > > ../../src/demo-1.C:7:7: note: candidate: ‘constexpr bar::bar(bar&&)’
> > > ../../src/demo-1.C:7:7: note:   candidate expects 1 argument, 0 provided
> > > 
> > > which shows the code that's leading to the error (the bad call to
> > > std::make_unique).
> > 
> > This is great!  I noticed however that the source code gets printed in a
> > surprising way in some contexts.  Consider:
> > 
> > template void f(typename T::type);
> > 
> > int main() {
> >   f(0);
> > }
> > 
> > For this testcase we emit:
> > 
> > testcase.C: In function ‘int main()’:
> > testcase.C:4:9: error: no matching function for call to ‘f(int)’
> > 4 |   f(0);
> >   |   ~~^~~
> > testcase.C:1:24: note: candidate: ‘template void f(typename 
> > T::type)’
> > 1 | template void f(typename T::type);
> >   |^
> > testcase.C:1:24: note:   template argument deduction/substitution failed:
> > testcase.C: In substitution of ‘template void f(typename T::type) 
> > [with T = int]’:
> > testcase.C:4:9:   required from here
> > testcase.C:1:24: note: 4 |   f(0);
> > testcase.C:1:24: note:   |   ~~^~~
> &

Re: [PATCH] c++/modules testsuite: avoid expensive ggc-min-expand=0

2024-04-24 Thread Patrick Palka
On Tue, 23 Apr 2024, Jason Merrill wrote:

> On 4/23/24 11:28, Patrick Palka wrote:
> > Tested on x86_64-pc-linux-gnu, does this look OK for trunk?
> 
> Is the test being run for multiple standard levels?  I'd rather restrict it to
> one and keep fully testing GC-safety.

Ah yeah, looks like it runs three times by default, in C++17, C++20 and
C++23 mode.  Like so?  The speedup is almost as good as using
ggc-min-expand=1.

Interestingly, restricting to one standard level _and_ using
ggc-min-expand=1 does not give further speedup.

-- >8 --

Subject: [PATCH] c++/modules testsuite: restrict expensive pr99023 test

The pr99023 testcase uses --param=ggc-min-expand=0 which forces a GC
during every collection point and consequently is very slow to run,
and ends up being the main bottleneck of the modules.exp testsuite.

So this patch restricts this test to run once, in C++20 mode, instead of
multiple times (C++17, C++20 and C++23 mode by default).  After this
patch the modules.exp testsuite finishes in 3m instead of 3m40s with -j8
on my machine.

gcc/testsuite/ChangeLog:

* g++.dg/modules/pr99023_a.X: Run only in C++20 mode.
* g++.dg/modules/pr99023_b.X: Likewise.
---
 gcc/testsuite/g++.dg/modules/pr99023_a.X | 1 +
 gcc/testsuite/g++.dg/modules/pr99023_b.X | 1 +
 2 files changed, 2 insertions(+)

diff --git a/gcc/testsuite/g++.dg/modules/pr99023_a.X 
b/gcc/testsuite/g++.dg/modules/pr99023_a.X
index c872d15f792..507e9569535 100644
--- a/gcc/testsuite/g++.dg/modules/pr99023_a.X
+++ b/gcc/testsuite/g++.dg/modules/pr99023_a.X
@@ -1,4 +1,5 @@
 // PR c++/99023, ICE
+// { dg-require-effective-target c++20_only }
 // { dg-additional-options {-x c++-system-header initializer_list -fmodules-ts 
--param ggc-min-expand=0} }
 
 // { dg-prune-output {linker input file unused} }
diff --git a/gcc/testsuite/g++.dg/modules/pr99023_b.X 
b/gcc/testsuite/g++.dg/modules/pr99023_b.X
index ca5f32e5bcc..59d32bee8d5 100644
--- a/gcc/testsuite/g++.dg/modules/pr99023_b.X
+++ b/gcc/testsuite/g++.dg/modules/pr99023_b.X
@@ -1,4 +1,5 @@
 // PR c++/99023, ICE
+// { dg-require-effective-target c++20_only }
 // { dg-additional-options {-x c++-system-header iostream -fmodules-ts 
-flang-info-include-translate= --param ggc-min-expand=0} }
 
 // { dg-prune-output {linker input file unused} }
-- 
2.45.0.rc0


> 
> > -- >8 --
> > 
> > The below testcase uses --param=ggc-min-expand=0 which forces a full GC
> > during every collection point and in turn takes over two minutes to run
> > and ends up being the main bottleneck of the modules.exp testsuite.
> > 
> > This patch speeds up this test without (hopefully) significantly affecting
> > its coverage by using =1 instead of =0 which forces a full GC each time the
> > heap grows by 1%, which means exponentially fewer GCs.  After this patch
> > the modules.exp testsuite finishes in 2m55s instead of 3m40s with -j8 on
> > my machine.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/modules/pr99023_a.X: Use ggc-min-expand=1 instead of =0.
> > * g++.dg/modules/pr99023_b.X: Likewise.
> > ---
> >   gcc/testsuite/g++.dg/modules/pr99023_a.X | 2 +-
> >   gcc/testsuite/g++.dg/modules/pr99023_b.X | 2 +-
> >   2 files changed, 2 insertions(+), 2 deletions(-)
> > 
> > diff --git a/gcc/testsuite/g++.dg/modules/pr99023_a.X
> > b/gcc/testsuite/g++.dg/modules/pr99023_a.X
> > index c872d15f792..96bb4a2ab5a 100644
> > --- a/gcc/testsuite/g++.dg/modules/pr99023_a.X
> > +++ b/gcc/testsuite/g++.dg/modules/pr99023_a.X
> > @@ -1,5 +1,5 @@
> >   // PR c++/99023, ICE
> > -// { dg-additional-options {-x c++-system-header initializer_list
> > -fmodules-ts --param ggc-min-expand=0} }
> > +// { dg-additional-options {-x c++-system-header initializer_list
> > -fmodules-ts --param ggc-min-expand=1} }
> > // { dg-prune-output {linker input file unused} }
> >   diff --git a/gcc/testsuite/g++.dg/modules/pr99023_b.X
> > b/gcc/testsuite/g++.dg/modules/pr99023_b.X
> > index ca5f32e5bcc..955378ad88f 100644
> > --- a/gcc/testsuite/g++.dg/modules/pr99023_b.X
> > +++ b/gcc/testsuite/g++.dg/modules/pr99023_b.X
> > @@ -1,5 +1,5 @@
> >   // PR c++/99023, ICE
> > -// { dg-additional-options {-x c++-system-header iostream -fmodules-ts
> > -flang-info-include-translate= --param ggc-min-expand=0} }
> > +// { dg-additional-options {-x c++-system-header iostream -fmodules-ts
> > -flang-info-include-translate= --param ggc-min-expand=1} }
> > // { dg-prune-output {linker input file unused} }
> >   
> 
> 



[PATCH] c++/modules testsuite: avoid expensive ggc-min-expand=0

2024-04-23 Thread Patrick Palka
Tested on x86_64-pc-linux-gnu, does this look OK for trunk?

-- >8 --

The below testcase uses --param=ggc-min-expand=0 which forces a full GC
during every collection point and in turn takes over two minutes to run
and ends up being the main bottleneck of the modules.exp testsuite.

This patch speeds up this test without (hopefully) significantly affecting
its coverage by using =1 instead of =0 which forces a full GC each time the
heap grows by 1%, which means exponentially fewer GCs.  After this patch
the modules.exp testsuite finishes in 2m55s instead of 3m40s with -j8 on
my machine.

gcc/testsuite/ChangeLog:

* g++.dg/modules/pr99023_a.X: Use ggc-min-expand=1 instead of =0.
* g++.dg/modules/pr99023_b.X: Likewise.
---
 gcc/testsuite/g++.dg/modules/pr99023_a.X | 2 +-
 gcc/testsuite/g++.dg/modules/pr99023_b.X | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/gcc/testsuite/g++.dg/modules/pr99023_a.X 
b/gcc/testsuite/g++.dg/modules/pr99023_a.X
index c872d15f792..96bb4a2ab5a 100644
--- a/gcc/testsuite/g++.dg/modules/pr99023_a.X
+++ b/gcc/testsuite/g++.dg/modules/pr99023_a.X
@@ -1,5 +1,5 @@
 // PR c++/99023, ICE
-// { dg-additional-options {-x c++-system-header initializer_list -fmodules-ts 
--param ggc-min-expand=0} }
+// { dg-additional-options {-x c++-system-header initializer_list -fmodules-ts 
--param ggc-min-expand=1} }
 
 // { dg-prune-output {linker input file unused} }
 
diff --git a/gcc/testsuite/g++.dg/modules/pr99023_b.X 
b/gcc/testsuite/g++.dg/modules/pr99023_b.X
index ca5f32e5bcc..955378ad88f 100644
--- a/gcc/testsuite/g++.dg/modules/pr99023_b.X
+++ b/gcc/testsuite/g++.dg/modules/pr99023_b.X
@@ -1,5 +1,5 @@
 // PR c++/99023, ICE
-// { dg-additional-options {-x c++-system-header iostream -fmodules-ts 
-flang-info-include-translate= --param ggc-min-expand=0} }
+// { dg-additional-options {-x c++-system-header iostream -fmodules-ts 
-flang-info-include-translate= --param ggc-min-expand=1} }
 
 // { dg-prune-output {linker input file unused} }
 
-- 
2.45.0.rc0



Re: [PATCH] c++/modules: deduced return type merging [PR114795]

2024-04-23 Thread Patrick Palka
On Tue, 23 Apr 2024, Patrick Palka wrote:
> Tested on x86_64-pc-linux-gnu, does this look OK for trunk?
> 
> -- >8 --
> 
> When merging an imported function template specialization with an
> existing one, if the existing one has an undeduced return type and the
> imported one's is already deduced, we need to propagate the deduced type
> since once we install the imported definition we won't get a chance to
> deduce it by normal means.
> 
> This patch makes is_matching_decl propagate the deduced return type
> alongside the existing propagate of the existing specification.  I

er, "alongside the existing propagation of the exception specification".

> suppose could instead propagate it later when installing the imported
> definition from read_definition, but it seems best to propagate it
> sooner rather than later.
> 
>   PR c++/114795
> 
> gcc/cp/ChangeLog:
> 
>   * module.cc (trees_in::is_matching_decl): Propagate deduced
>   function return type.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/modules/auto-4_a.H: New test.
>   * g++.dg/modules/auto-4_b.C: New test.
> ---
>  gcc/cp/module.cc|  5 +
>  gcc/testsuite/g++.dg/modules/auto-4_a.H | 14 ++
>  gcc/testsuite/g++.dg/modules/auto-4_b.C | 15 +++
>  3 files changed, 34 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/modules/auto-4_a.H
>  create mode 100644 gcc/testsuite/g++.dg/modules/auto-4_b.C
> 
> diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> index d94d8ff4df9..e10e19ac9f7 100644
> --- a/gcc/cp/module.cc
> +++ b/gcc/cp/module.cc
> @@ -11537,6 +11537,11 @@ trees_in::is_matching_decl (tree existing, tree 
> decl, bool is_typedef)
>else if (!DEFERRED_NOEXCEPT_SPEC_P (d_spec)
>  && !comp_except_specs (d_spec, e_spec, ce_type))
>   goto mismatch;
> +
> +  /* Similarly if EXISTING has an undeduced return type, but DECL's
> +  is already deduced.  */
> +  if (undeduced_auto_decl (existing) && !undeduced_auto_decl (decl))
> + TREE_TYPE (existing) = change_return_type (TREE_TYPE (d_type), e_type);
>  }
>else if (is_typedef)
>  {
> diff --git a/gcc/testsuite/g++.dg/modules/auto-4_a.H 
> b/gcc/testsuite/g++.dg/modules/auto-4_a.H
> new file mode 100644
> index 000..52b50533982
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/modules/auto-4_a.H
> @@ -0,0 +1,14 @@
> +// PR c++/114795
> +// { dg-additional-options "-fmodule-header" }
> +// { dg-module-cmi {} }
> +
> +template
> +struct A {
> +  auto f() { return 0; }

Oops, this should be "return T();" to match the other definition below.

> +};
> +
> +template
> +inline void g() {
> +  A a;
> +  a.f();
> +}
> diff --git a/gcc/testsuite/g++.dg/modules/auto-4_b.C 
> b/gcc/testsuite/g++.dg/modules/auto-4_b.C
> new file mode 100644
> index 000..378684ef6d0
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/modules/auto-4_b.C
> @@ -0,0 +1,15 @@
> +// PR c++/114795
> +// { dg-additional-options "-fmodules-ts -fno-module-lazy" }
> +
> +template
> +struct A {
> +  auto f() { return T(); }
> +};
> +
> +A a;
> +
> +import "auto-4_a.H";
> +
> +int main() {
> +  g(); // { dg-bogus "before deduction of 'auto'" "" { target *-*-* } 0 
> }
> +}
> -- 
> 2.45.0.rc0
> 
> 



[PATCH] c++/modules: deduced return type merging [PR114795]

2024-04-23 Thread Patrick Palka
Tested on x86_64-pc-linux-gnu, does this look OK for trunk?

-- >8 --

When merging an imported function template specialization with an
existing one, if the existing one has an undeduced return type and the
imported one's is already deduced, we need to propagate the deduced type
since once we install the imported definition we won't get a chance to
deduce it by normal means.

This patch makes is_matching_decl propagate the deduced return type
alongside the existing propagate of the existing specification.  I
suppose could instead propagate it later when installing the imported
definition from read_definition, but it seems best to propagate it
sooner rather than later.

PR c++/114795

gcc/cp/ChangeLog:

* module.cc (trees_in::is_matching_decl): Propagate deduced
function return type.

gcc/testsuite/ChangeLog:

* g++.dg/modules/auto-4_a.H: New test.
* g++.dg/modules/auto-4_b.C: New test.
---
 gcc/cp/module.cc|  5 +
 gcc/testsuite/g++.dg/modules/auto-4_a.H | 14 ++
 gcc/testsuite/g++.dg/modules/auto-4_b.C | 15 +++
 3 files changed, 34 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/modules/auto-4_a.H
 create mode 100644 gcc/testsuite/g++.dg/modules/auto-4_b.C

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index d94d8ff4df9..e10e19ac9f7 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -11537,6 +11537,11 @@ trees_in::is_matching_decl (tree existing, tree decl, 
bool is_typedef)
   else if (!DEFERRED_NOEXCEPT_SPEC_P (d_spec)
   && !comp_except_specs (d_spec, e_spec, ce_type))
goto mismatch;
+
+  /* Similarly if EXISTING has an undeduced return type, but DECL's
+is already deduced.  */
+  if (undeduced_auto_decl (existing) && !undeduced_auto_decl (decl))
+   TREE_TYPE (existing) = change_return_type (TREE_TYPE (d_type), e_type);
 }
   else if (is_typedef)
 {
diff --git a/gcc/testsuite/g++.dg/modules/auto-4_a.H 
b/gcc/testsuite/g++.dg/modules/auto-4_a.H
new file mode 100644
index 000..52b50533982
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/auto-4_a.H
@@ -0,0 +1,14 @@
+// PR c++/114795
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+template
+struct A {
+  auto f() { return 0; }
+};
+
+template
+inline void g() {
+  A a;
+  a.f();
+}
diff --git a/gcc/testsuite/g++.dg/modules/auto-4_b.C 
b/gcc/testsuite/g++.dg/modules/auto-4_b.C
new file mode 100644
index 000..378684ef6d0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/auto-4_b.C
@@ -0,0 +1,15 @@
+// PR c++/114795
+// { dg-additional-options "-fmodules-ts -fno-module-lazy" }
+
+template
+struct A {
+  auto f() { return T(); }
+};
+
+A a;
+
+import "auto-4_a.H";
+
+int main() {
+  g(); // { dg-bogus "before deduction of 'auto'" "" { target *-*-* } 0 }
+}
-- 
2.45.0.rc0



[PATCH] c++: constexpr union member access folding [PR114709]

2024-04-22 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
for trunk/13/12?

-- >8 --

The object/offset canonicalization performed in cxx_fold_indirect_ref
is undesirable for union member accesses because it loses information
about the member being accessed which we may later need to diagnose an
inactive-member access.  So this patch restricts the canonicalization
accordingly.

PR c++/114709

gcc/cp/ChangeLog:

* constexpr.cc (cxx_fold_indirect_ref): Restrict object/offset
canonicalization to RECORD_TYPE member accesses.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/constexpr-union8.C: New test.
---
 gcc/cp/constexpr.cc   | 1 +
 gcc/testsuite/g++.dg/cpp0x/constexpr-union8.C | 8 
 2 files changed, 9 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-union8.C

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index fcc847d85df..941a478e889 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -5797,6 +5797,7 @@ cxx_fold_indirect_ref (const constexpr_ctx *ctx, 
location_t loc, tree type,
  more folding opportunities.  */
   auto canonicalize_obj_off = [] (tree& obj, tree& off) {
 while (TREE_CODE (obj) == COMPONENT_REF
+  && TREE_CODE (TREE_TYPE (TREE_OPERAND (obj, 0))) == RECORD_TYPE
   && (tree_int_cst_sign_bit (off) || integer_zerop (off)))
   {
tree field = TREE_OPERAND (obj, 1);
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-union8.C 
b/gcc/testsuite/g++.dg/cpp0x/constexpr-union8.C
new file mode 100644
index 000..34c264944b6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-union8.C
@@ -0,0 +1,8 @@
+// PR c++/114709
+// { dg-do compile { target c++11 } }
+
+struct T1 { int a, b; };
+struct T2 { int c; double d; };
+union U { T1 t1; T2 t2; };
+
+constexpr int v = U{{1,2}}.t2.*::c; // { dg-error "accessing 'U::t2'" }
-- 
2.45.0.rc0



[PATCH] libstdc++: Implement ranges::concat_view from P2542R7

2024-04-22 Thread Patrick Palka
Tested on x86_64-pc-linux-gnu, does this look OK for trunk?  More tests
are needed but I figured I'd submit this now for possible consideration into
GCC 14 since we're getting close to release..  All changes are confined to
C++26.

-- >8 --

libstdc++-v3/ChangeLog:

* include/bits/version.def (ranges_concat): Define.
* include/bits/version.h: Regenerate.
* include/std/ranges (__detail::__concat_reference_t): Define
for C++26.
(__detail::__concat_value_t): Likewise.
(__detail::__concat_rvalue_reference_t): Likewise.
(__detail::__concat_indirectly_readable_impl): Likewise.
(__detail::__concat_indirectly_readable): Likewise.
(__detail::__concatable): Likewise.
(__detail::__all_but_last_common): Likewise.
(__detail::__concat_is_random_access): Likewise.
(__detail::__concat_is_bidirectional): Likewise.
(__detail::__last_is_common): Likewise.
(concat_view): Likewise.
(__detail::__concat_view_iter_cat): Likewise.
(concat_view::iterator): Likewise.
(views::__detail::__can_concat_view): Likewise.
(views::_Concat, views::concat): Likewise.
* testsuite/std/ranges/concat/1.cc: New test.
---
 libstdc++-v3/include/bits/version.def |   8 +
 libstdc++-v3/include/bits/version.h   |  10 +
 libstdc++-v3/include/std/ranges   | 584 ++
 libstdc++-v3/testsuite/std/ranges/concat/1.cc |  61 ++
 4 files changed, 663 insertions(+)
 create mode 100644 libstdc++-v3/testsuite/std/ranges/concat/1.cc

diff --git a/libstdc++-v3/include/bits/version.def 
b/libstdc++-v3/include/bits/version.def
index 5c0477fb61e..af13090c094 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -1796,6 +1796,14 @@ ftms = {
   };
 };
 
+ftms = {
+  name = ranges_concat;
+  values = {
+v = 202403;
+cxxmin = 26;
+  };
+};
+
 // Standard test specifications.
 stds[97] = ">= 199711L";
 stds[03] = ">= 199711L";
diff --git a/libstdc++-v3/include/bits/version.h 
b/libstdc++-v3/include/bits/version.h
index 65e708c73fb..1f27bfe050d 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -2003,4 +2003,14 @@
 #endif /* !defined(__cpp_lib_to_string) && defined(__glibcxx_want_to_string) */
 #undef __glibcxx_want_to_string
 
+#if !defined(__cpp_lib_ranges_concat)
+# if (__cplusplus >  202302L)
+#  define __glibcxx_ranges_concat 202403L
+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges_concat)
+#   define __cpp_lib_ranges_concat 202403L
+#  endif
+# endif
+#endif /* !defined(__cpp_lib_ranges_concat) && 
defined(__glibcxx_want_ranges_concat) */
+#undef __glibcxx_want_ranges_concat
+
 #undef __glibcxx_want_all
diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index afce818376b..28a39bf6f34 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -55,6 +55,7 @@
 #define __glibcxx_want_ranges_as_const
 #define __glibcxx_want_ranges_as_rvalue
 #define __glibcxx_want_ranges_cartesian_product
+#define __glibcxx_want_ranges_concat
 #define __glibcxx_want_ranges_chunk
 #define __glibcxx_want_ranges_chunk_by
 #define __glibcxx_want_ranges_enumerate
@@ -9514,6 +9515,589 @@ namespace __detail
 } // namespace ranges
 #endif // __cpp_lib_ranges_to_container
 
+#if __cpp_lib_ranges_concat // C++ >= C++26
+namespace ranges
+{
+  namespace __detail
+  {
+template
+  using __concat_reference_t = 
common_reference_t...>;
+
+template
+  using __concat_value_t = common_type_t...>;
+
+template
+  using __concat_rvalue_reference_t
+   = common_reference_t...>;
+
+template
+  concept __concat_indirectly_readable_impl = requires (const _It __it) {
+   { *__it } -> convertible_to<_Ref>;
+   { ranges::iter_move(__it) } -> convertible_to<_RRef>;
+  };
+
+template
+  concept __concat_indirectly_readable
+   = common_reference_with<__concat_reference_t<_Rs...>&&, 
__concat_value_t<_Rs...>&>
+ && common_reference_with<__concat_reference_t<_Rs...>&&,
+  __concat_rvalue_reference_t<_Rs...>&&>
+ && common_reference_with<__concat_rvalue_reference_t<_Rs...>&&,
+  __concat_value_t<_Rs...> const&>
+ && (__concat_indirectly_readable_impl<__concat_reference_t<_Rs...>,
+   
__concat_rvalue_reference_t<_Rs...>,
+   iterator_t<_Rs>>
+ && ...);
+
+template
+  concept __concatable = requires {
+   typename __concat_reference_t<_Rs...>;
+   typename __concat_value_t<_Rs...>;
+   typename __concat_rvalue_reference_t<_Rs...>;
+  } && __concat_indirectly_readable<_Rs...>;
+
+template
+  struct __all_but_last_common
+  {
+   static inline constexpr bool value
+ = requires { 

Re: [pushed] c++/modules: make bits_in/out move-constructible

2024-04-22 Thread Patrick Palka
On Mon, 22 Apr 2024, Christophe Lyon wrote:

> Hi Patrick,
> 
> On Sat, 13 Apr 2024 at 22:12, Patrick Palka  wrote:
> >
> > Pushed as obvious after verifying C++11 bootstrap is restored.
> 
> I guess this also fixes the bootstrap_ubsan breakage on aarch64
> reported by Linaro CI?
> See https://linaro.atlassian.net/browse/GNU-1199
> (I think you also received a notification about this a few days ago?)

Yes, sorry for the breakage.  r14-9955-g436ab7e8e8b broke bootstrap
due to relying on C++17 copy elision semantics, and this followup
patch trivially fixed that.

> 
> Thanks,
> 
> Christophe
> 
> >
> > -- >8 --
> >
> > gcc/cp/ChangeLog:
> >
> > * module.cc (struct bytes_in::bits_in): Define defaulted
> > move ctor.
> > (struct bytes_out::bits_out): Likewise.
> > ---
> >  gcc/cp/module.cc | 2 ++
> >  1 file changed, 2 insertions(+)
> >
> > diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> > index bbed82652d4..c6f71e11515 100644
> > --- a/gcc/cp/module.cc
> > +++ b/gcc/cp/module.cc
> > @@ -706,6 +706,7 @@ struct bytes_in::bits_in {
> >  bflush ();
> >}
> >
> > +  bits_in(bits_in&&) = default;
> >bits_in(const bits_in&) = delete;
> >bits_in& operator=(const bits_in&) = delete;
> >
> > @@ -752,6 +753,7 @@ struct bytes_out::bits_out {
> >  bflush ();
> >}
> >
> > +  bits_out(bits_out&&) = default;
> >bits_out(const bits_out&) = delete;
> >bits_out& operator=(const bits_out&) = delete;
> >
> > --
> > 2.44.0.591.g8f7582d995
> >
> 
> 



Re: [PATCH] c++: Check if allocation functions are xobj members [PR114078]

2024-04-21 Thread Patrick Palka
On Sat, 20 Apr 2024, Nathaniel Shead wrote:

> Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?
> 
> -- >8 --
> 
> A class allocation member function is implicitly 'static' by
> [class.free] p3, so cannot have an explicit object parameter.
> 
>   PR c++/114078
> 
> gcc/cp/ChangeLog:
> 
>   * decl.cc (grokdeclarator): Check allocation functions for xobj
>   parameters.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp23/explicit-obj-ops-alloc.C: New test.

LGTM

> 
> Signed-off-by: Nathaniel Shead 
> ---
>  gcc/cp/decl.cc  |  6 ++
>  gcc/testsuite/g++.dg/cpp23/explicit-obj-ops-alloc.C | 11 +++
>  2 files changed, 17 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/cpp23/explicit-obj-ops-alloc.C
> 
> diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> index 65ab64885ff..2af026d255d 100644
> --- a/gcc/cp/decl.cc
> +++ b/gcc/cp/decl.cc
> @@ -13728,6 +13728,12 @@ grokdeclarator (const cp_declarator *declarator,
>   inform (DECL_SOURCE_LOCATION (xobj_parm),
>   "explicit object parameter declared here");
> }
> + if (unqualified_id
> + && identifier_p (unqualified_id)
> + && IDENTIFIER_NEWDEL_OP_P (unqualified_id))
> +   error_at (DECL_SOURCE_LOCATION (xobj_parm),
> + "%qD cannot be an explicit object member "
> + "function", unqualified_id);
> }
> }
>   tree pushed_scope = NULL_TREE;
> diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-ops-alloc.C 
> b/gcc/testsuite/g++.dg/cpp23/explicit-obj-ops-alloc.C
> new file mode 100644
> index 000..8a277db7ef5
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-ops-alloc.C
> @@ -0,0 +1,11 @@
> +// PR c++/114078
> +// { dg-do compile { target c++23 } }
> +
> +using size_t = decltype(sizeof(0));
> +
> +struct S {
> +  void* operator new(this size_t);  // { dg-error "explicit object" }
> +  void* operator new[](this size_t);  // { dg-error "explicit object" }
> +  void operator delete(this void*);  // { dg-error "explicit object" }
> +  void operator delete[](this void*);  // { dg-error "explicit object" }
> +};
> -- 
> 2.43.2
> 
> 



Re: [PATCH] c++: Fix ICE with xobj parms and maybe incomplete decl-specifiers

2024-04-21 Thread Patrick Palka
> Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?
> 
> -- >8 --
> 
> This fixes a null dereference issue when decl_specifiers.type is not yet
> provided.
> 
> gcc/cp/ChangeLog:
> 
>   * parser.cc (cp_parser_parameter_declaration): Check if
>   decl_specifiers.type is null.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp23/explicit-obj-basic7.C: New test.

LGTM

> 
> Signed-off-by: Nathaniel Shead 
> ---
>  gcc/cp/parser.cc | 5 +++--
>  gcc/testsuite/g++.dg/cpp23/explicit-obj-basic7.C | 9 +
>  2 files changed, 12 insertions(+), 2 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp23/explicit-obj-basic7.C
> 
> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> index 50d3ad35b61..97ee2650dc4 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -25780,8 +25780,9 @@ cp_parser_parameter_declaration (cp_parser *parser,
>  }
>  
>if (xobj_param_p
> -  && (declarator ? declarator->parameter_pack_p
> -  : PACK_EXPANSION_P (decl_specifiers.type)))
> +  && ((declarator && declarator->parameter_pack_p)
> +   || (decl_specifiers.type
> +   && PACK_EXPANSION_P (decl_specifiers.type
>  {
>location_t xobj_param
>   = make_location (decl_specifiers.locations[ds_this],
> diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-basic7.C 
> b/gcc/testsuite/g++.dg/cpp23/explicit-obj-basic7.C
> new file mode 100644
> index 000..a474e97fc18
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-basic7.C
> @@ -0,0 +1,9 @@
> +// { dg-do compile { target c++23 } }
> +
> +// Shouldn't ICE
> +struct S {
> +  void a(this long);
> +  void b(this const long);
> +  void c(this long unsigned);
> +  void c(this signed);
> +};
> -- 
> 2.43.2
> 
> 



Re: [PATCH] libstdc++: Fix std::ranges::iota is not included in numeric [PR108760]

2024-04-18 Thread Patrick Palka
On Wed, 17 Apr 2024, Michael Levine (BLOOMBERG/ 919 3RD A) wrote:

> This patch fixes GCC Bug 108760: 
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108760
> Before this patch, using std::ranges::iota required including  
> when it should have been sufficient to only include .
> 
> When the patch is applied, the following code will compile: 
> https://godbolt.org/z/33EPeqd1b
> 
> I added a test case for this change as well.
> 
> I built my local version of gcc using the following configuration: $ 
> ../gcc/configure --disable-bootstrap --prefix="$(pwd)/_pfx/" 
> --enable-languages=c,c++,lto
> 
> and I tested my changes by running: $ make check-c++ -jN -k

Nice, thanks for the patch!

> 
> I ran this on the following OS:
> 
> Virtualization: wsl
> Operating System: Ubuntu 20.04.6 LTS
> Kernel: Linux 5.15.146.1-microsoft-standard-WSL2
> Architecture: x86-64

> From bd04070c281572ed7a3b48e3d33543e25b8c8afe Mon Sep 17 00:00:00 2001
> From: Michael Levine 
> Date: Fri, 23 Feb 2024 14:13:13 -0500
> Subject: [PATCH 1/2] Fix the bug
> 
> Signed-off-by: Michael Levine 
> ---
>  libstdc++-v3/include/bits/ranges_algo.h | 52 --
>  libstdc++-v3/include/bits/stl_numeric.h | 57 -
>  2 files changed, 56 insertions(+), 53 deletions(-)
> 
> diff --git a/libstdc++-v3/include/bits/ranges_algo.h 
> b/libstdc++-v3/include/bits/ranges_algo.h
> index 62faff173bd..d258be0b93f 100644
> --- a/libstdc++-v3/include/bits/ranges_algo.h
> +++ b/libstdc++-v3/include/bits/ranges_algo.h
> @@ -3521,58 +3521,6 @@ namespace ranges
>  
>  #endif // __glibcxx_ranges_contains
>  
> -#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
> -
> -  template
> -struct out_value_result
> -{
> -  [[no_unique_address]] _Out out;
> -  [[no_unique_address]] _Tp value;
> -
> -  template
> - requires convertible_to
> -   && convertible_to
> - constexpr
> - operator out_value_result<_Out2, _Tp2>() const &
> - { return {out, value}; }
> -
> -  template
> - requires convertible_to<_Out, _Out2>
> -   && convertible_to<_Tp, _Tp2>
> - constexpr
> - operator out_value_result<_Out2, _Tp2>() &&
> - { return {std::move(out), std::move(value)}; }
> -};
> -
> -  template
> -using iota_result = out_value_result<_Out, _Tp>;
> -
> -  struct __iota_fn
> -  {
> -template _Sent, 
> weakly_incrementable _Tp>
> -  requires indirectly_writable<_Out, const _Tp&>
> -  constexpr iota_result<_Out, _Tp>
> -  operator()(_Out __first, _Sent __last, _Tp __value) const
> -  {
> - while (__first != __last)
> -   {
> - *__first = static_cast(__value);
> - ++__first;
> - ++__value;
> -   }
> - return {std::move(__first), std::move(__value)};
> -  }
> -
> -template _Range>
> -  constexpr iota_result, _Tp>
> -  operator()(_Range&& __r, _Tp __value) const
> -  { return (*this)(ranges::begin(__r), ranges::end(__r), 
> std::move(__value)); }
> -  };
> -
> -  inline constexpr __iota_fn iota{};
> -
> -#endif // __glibcxx_ranges_iota
> -
>  #if __glibcxx_ranges_find_last >= 202207L // C++ >= 23
>  
>struct __find_last_fn
> diff --git a/libstdc++-v3/include/bits/stl_numeric.h 
> b/libstdc++-v3/include/bits/stl_numeric.h
> index fe911154ab7..1b06c26dc02 100644
> --- a/libstdc++-v3/include/bits/stl_numeric.h
> +++ b/libstdc++-v3/include/bits/stl_numeric.h
> @@ -59,7 +59,7 @@
>  #include 
>  #include 
>  #include  // For _GLIBCXX_MOVE
> -
> +#include  // For _Range as used by std::ranges::iota
>  
>  namespace std _GLIBCXX_VISIBILITY(default)
>  {
> @@ -102,6 +102,61 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>  }
>  #endif
>  
> +namespace ranges
> +{
> +#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
> +
> +  template
> +struct out_value_result
> +{
> +  [[no_unique_address]] _Out out;
> +  [[no_unique_address]] _Tp value;
> +
> +  template
> + requires convertible_to
> +   && convertible_to
> + constexpr
> + operator out_value_result<_Out2, _Tp2>() const &
> + { return {out, value}; }
> +
> +  template
> + requires convertible_to<_Out, _Out2>
> +   && convertible_to<_Tp, _Tp2>
> + constexpr
> + operator out_value_result<_Out2, _Tp2>() &&
> + { return {std::move(out), std::move(value)}; }
> +};

IIUC out_value_result should continue to be available from , so we
probably don't want to move it to  (or one of its internal headers).
Better would be to move it to  I think.

> +
> +  template
> +using iota_result = out_value_result<_Out, _Tp>;
> +
> +  struct __iota_fn
> +  {
> +template _Sent, 
> weakly_incrementable _Tp>
> +  requires indirectly_writable<_Out, const _Tp&>
> +  constexpr iota_result<_Out, _Tp>
> +  operator()(_Out __first, _Sent __last, _Tp __value) const
> +  {
> + while (__first != __last)
> +   {
> + *__first = static_cast(__value);
> + ++__first;
> + ++__value;
> +  

Re: [PATCH v2 2/2] c++/modules: Fix instantiation of imported temploid friends [PR114275]

2024-04-17 Thread Patrick Palka
On Mon, 15 Apr 2024, Nathaniel Shead wrote:

> I'm not a huge fan of always streaming 'imported_temploid_friends' for
> all decls, but I don't think it adds much performance cost over adding a
> new flag to categorise decls that might be marked as such.

IIUC this value is going to be almost always null which is encoded as a
single 0 byte, which should be fast to stream.  But I wonder how much
larger  gets?  Can we get away with streaming this value
only for TEMPLATE_DECLs?

> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?
> 
> -- >8 --
> 
> This patch fixes a number of issues with the handling of temploid friend
> declarations.
> 
> The primary issue is that instantiations of friend declarations should
> attach the declaration to the same module as the befriending class, by
> [module.unit] p7.1 and [temp.friend] p2; this could be a different
> module from the current TU, and so needs special handling.

Nice, your approach seems consistent with Nathan's comments in the past
about this issue:

https://gcc.gnu.org/pipermail/gcc-patches/2022-October/603288.html
https://gcc.gnu.org/pipermail/gcc-patches/2023-February/611215.htmlw

> 
> The other main issue here is that we can't assume that just because name
> lookup didn't find a definition for a hidden template class, it doesn't
> mean that it doesn't exist: it could be a non-exported entity that we've
> nevertheless streamed in from an imported module.  We need to ensure
> that when instantiating friend classes that we return the same TYPE_DECL
> that we got from our imports, otherwise we will get later issues with
> 'duplicate_decls' (rightfully) complaining that they're different.
> 
> This doesn't appear necessary for functions due to the existing name
> lookup handling already finding these hidden declarations.

It does seem like a weird inconsistency that tsubst_friend_class needs
this workaround but not tsubst_friend_function.

I wonder if we can relax duplicate_decls to treat an instantiated
template friend class as a redeclaration instead of complaining,
mirroring its behavior for functions, which in turn would let us get rid
of the name lookup in tsubst_friend_class and eliminate the need for
lookup_imported_hidden_friend?  This may be too speculative/risky of
a refactoring at this stage though, and your approach has the nice
advantage of changing only modules code paths.

In any case I hope we can fix this issue for GCC 14!  LGTM overall.

> 
>   PR c++/105320
>   PR c++/114275
> 
> gcc/cp/ChangeLog:
> 
>   * cp-tree.h (propagate_defining_module): Declare.
>   (lookup_imported_hidden_friend): Declare.
>   * decl.cc (duplicate_decls): Also check if hidden declarations
>   can be redeclared in this module.
>   * module.cc (imported_temploid_friends): New map.
>   (init_modules): Initialize it.
>   (trees_out::decl_value): Write it.
>   (trees_in::decl_value): Read it.
>   (get_originating_module_decl): Follow the owning decl for an
>   imported temploid friend.
>   (propagate_defining_module): New function.
>   * name-lookup.cc (lookup_imported_hidden_friend): New function.
>   * pt.cc (tsubst_friend_function): Propagate defining module for
>   new friend functions.
>   (tsubst_friend_class): Lookup imported hidden friends. Check
>   for valid redeclaration. Propagate defining module for new
>   friend classes.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/modules/tpl-friend-10_a.C: New test.
>   * g++.dg/modules/tpl-friend-10_b.C: New test.
>   * g++.dg/modules/tpl-friend-10_c.C: New test.
>   * g++.dg/modules/tpl-friend-11_a.C: New test.
>   * g++.dg/modules/tpl-friend-11_b.C: New test.
>   * g++.dg/modules/tpl-friend-12_a.C: New test.
>   * g++.dg/modules/tpl-friend-12_b.C: New test.
>   * g++.dg/modules/tpl-friend-12_c.C: New test.
>   * g++.dg/modules/tpl-friend-12_d.C: New test.
>   * g++.dg/modules/tpl-friend-12_e.C: New test.
>   * g++.dg/modules/tpl-friend-12_f.C: New test.
>   * g++.dg/modules/tpl-friend-13_a.C: New test.
>   * g++.dg/modules/tpl-friend-13_b.C: New test.
>   * g++.dg/modules/tpl-friend-13_c.C: New test.
>   * g++.dg/modules/tpl-friend-13_d.C: New test.
>   * g++.dg/modules/tpl-friend-13_e.C: New test.
>   * g++.dg/modules/tpl-friend-9.C: New test.
> 
> Signed-off-by: Nathaniel Shead 
> ---
>  gcc/cp/cp-tree.h  |  2 +
>  gcc/cp/decl.cc| 36 +++--
>  gcc/cp/module.cc  | 52 +++
>  gcc/cp/name-lookup.cc | 42 +++
>  gcc/cp/pt.cc  | 19 +++
>  .../g++.dg/modules/tpl-friend-10_a.C  | 15 ++
>  .../g++.dg/modules/tpl-friend-10_b.C  |  5 ++
>  .../g++.dg/modules/tpl-friend-10_c.C  |  7 +++
>  .../g++.dg/modules/tpl-friend-11_a.C  | 14 +
>  

Re: [PATCH v2 1/2] c++: Standardise errors for module_may_redeclare

2024-04-17 Thread Patrick Palka
On Mon, 15 Apr 2024, Nathaniel Shead wrote:

> I took another look at this patch and have split it into two, one (this
> one) to standardise the error messages used and prepare
> 'module_may_redeclare' for use with temploid friends, and another
> followup patch to actually handle them correctly.
> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?

LGTM

> 
> -- >8 --
> 
> Currently different places calling 'module_may_redeclare' all emit very
> similar but slightly different error messages, and handle different
> kinds of declarations differently.  This patch makes the function
> perform its own error messages so that they're all in one place, and
> prepares it for use with temploid friends (PR c++/114275).
> 
> gcc/cp/ChangeLog:
> 
>   * cp-tree.h (module_may_redeclare): Add default parameter.
>   * decl.cc (duplicate_decls): Don't emit errors for failed
>   module_may_redeclare.
>   (xref_tag): Likewise.
>   (start_enum): Likewise.
>   * semantics.cc (begin_class_definition): Likewise.
>   * module.cc (module_may_redeclare): Clean up logic. Emit error
>   messages on failure.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/modules/enum-12.C: Update error message.
>   * g++.dg/modules/friend-5_b.C: Likewise.
>   * g++.dg/modules/shadow-1_b.C: Likewise.
> 
> Signed-off-by: Nathaniel Shead 
> ---
>  gcc/cp/cp-tree.h  |   2 +-
>  gcc/cp/decl.cc|  28 +
>  gcc/cp/module.cc  | 120 ++
>  gcc/cp/semantics.cc   |   6 +-
>  gcc/testsuite/g++.dg/modules/enum-12.C|   2 +-
>  gcc/testsuite/g++.dg/modules/friend-5_b.C |   2 +-
>  gcc/testsuite/g++.dg/modules/shadow-1_b.C |   5 +-
>  7 files changed, 89 insertions(+), 76 deletions(-)
> 
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 1dbb577a38d..faa7a0052a5 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -7401,7 +7401,7 @@ inline bool module_exporting_p ()
>  
>  extern module_state *get_module (tree name, module_state *parent = NULL,
>bool partition = false);
> -extern bool module_may_redeclare (tree decl);
> +extern bool module_may_redeclare (tree olddecl, tree newdecl = NULL);
>  
>  extern bool module_global_init_needed ();
>  extern bool module_determine_import_inits ();
> diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> index 65ab64885ff..aa66da4829d 100644
> --- a/gcc/cp/decl.cc
> +++ b/gcc/cp/decl.cc
> @@ -2279,18 +2279,8 @@ duplicate_decls (tree newdecl, tree olddecl, bool 
> hiding, bool was_hidden)
>&& TREE_CODE (olddecl) != NAMESPACE_DECL
>&& !hiding)
>  {
> -  if (!module_may_redeclare (olddecl))
> - {
> -   if (DECL_ARTIFICIAL (olddecl))
> - error ("declaration %qD conflicts with builtin", newdecl);
> -   else
> - {
> -   error ("declaration %qD conflicts with import", newdecl);
> -   inform (olddecl_loc, "import declared %q#D here", olddecl);
> - }
> -
> -   return error_mark_node;
> - }
> +  if (!module_may_redeclare (olddecl, newdecl))
> + return error_mark_node;
>  
>tree not_tmpl = STRIP_TEMPLATE (olddecl);
>if (DECL_LANG_SPECIFIC (not_tmpl)
> @@ -16620,12 +16610,7 @@ xref_tag (enum tag_types tag_code, tree name,
>   {
> tree decl = TYPE_NAME (t);
> if (!module_may_redeclare (decl))
> - {
> -   auto_diagnostic_group d;
> -   error ("cannot declare %qD in a different module", decl);
> -   inform (DECL_SOURCE_LOCATION (decl), "previously declared here");
> -   return error_mark_node;
> - }
> + return error_mark_node;
>  
> tree not_tmpl = STRIP_TEMPLATE (decl);
> if (DECL_LANG_SPECIFIC (not_tmpl)
> @@ -16973,12 +16958,7 @@ start_enum (tree name, tree enumtype, tree 
> underlying_type,
>   {
> tree decl = TYPE_NAME (enumtype);
> if (!module_may_redeclare (decl))
> - {
> -   auto_diagnostic_group d;
> -   error ("cannot declare %qD in different module", decl);
> -   inform (DECL_SOURCE_LOCATION (decl), "previously declared here");
> -   enumtype = error_mark_node;
> - }
> + enumtype = error_mark_node;
> else
>   set_instantiating_module (decl);
>   }
> diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> index 001430a4a8f..e2d2910ae48 100644
> --- a/gcc/cp/module.cc
> +++ b/gcc/cp/module.cc
> @@ -18992,11 +18992,15 @@ get_importing_module (tree decl, bool flexible)
>return module->mod;
>  }
>  
> -/* Is it permissible to redeclare DECL.  */
> +/* Is it permissible to redeclare OLDDECL with NEWDECL.
> +
> +   If NEWDECL is NULL, assumes that OLDDECL will be redeclared using
> +   the current scope's module and attachment.  */
>  
>  bool
> -module_may_redeclare (tree decl)
> +module_may_redeclare (tree olddecl, tree newdecl)
>  

[pushed] c++/modules: make bits_in/out move-constructible

2024-04-13 Thread Patrick Palka
Pushed as obvious after verifying C++11 bootstrap is restored.

-- >8 --

gcc/cp/ChangeLog:

* module.cc (struct bytes_in::bits_in): Define defaulted
move ctor.
(struct bytes_out::bits_out): Likewise.
---
 gcc/cp/module.cc | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index bbed82652d4..c6f71e11515 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -706,6 +706,7 @@ struct bytes_in::bits_in {
 bflush ();
   }
 
+  bits_in(bits_in&&) = default;
   bits_in(const bits_in&) = delete;
   bits_in& operator=(const bits_in&) = delete;
 
@@ -752,6 +753,7 @@ struct bytes_out::bits_out {
 bflush ();
   }
 
+  bits_out(bits_out&&) = default;
   bits_out(const bits_out&) = delete;
   bits_out& operator=(const bits_out&) = delete;
 
-- 
2.44.0.591.g8f7582d995



Re: [PATCH] c++/modules: optimize tree flag streaming

2024-04-13 Thread Patrick Palka
On Sat, 13 Apr 2024, Iain Sandoe wrote:

> Hi Patrick,
> 
> > On 10 Apr 2024, at 17:33, Jason Merrill  wrote:
> > 
> > On 4/10/24 11:26, Patrick Palka wrote:
> >> On Wed, 10 Apr 2024, Patrick Palka wrote:
> >>> 
> >>> On Tue, 9 Apr 2024, Jason Merrill wrote:
> >>> 
> >>>> On 2/16/24 10:06, Patrick Palka wrote:
> >>>>> On Thu, 15 Feb 2024, Patrick Palka wrote:
> >>>>> 
> 
> 
> 
> > Let's keep documenting the inheritance relationship here, i.e.
> > 
> >  bytes_in : data
> > 
> >> @@ -694,13 +656,132 @@ protected:
> >>/* Instrumentation.  */
> >>static unsigned spans[4];
> >>static unsigned lengths[4];
> >> -  static int is_set;
> >> +  friend struct bits_out;
> > 
> > It might be a little more elegant for bits_in/out to be nested classes of 
> > bytes_in/out, returned from member functions, rather than friends 
> > constructed directly?  OK either way, with the above comment tweak.
> 
> Unfortunately, this seems to break x86_64 Darwin bootstrap with fails as 
> below - I did not yet have a chance to look in any morre detail, so this is a 
> head’s up - unless you have any immediate ideas?
> 
> thanks
> Iain
> 
> 
> /src-local/gcc-master/gcc/cp/module.cc: In member function 
> ‘{anonymous}::bytes_in::bits_in {anonymous}::bytes_in::stream_bits()’:
> /src-local/gcc-master/gcc/cp/module.cc:735:24: error: use of deleted function 
> ‘{anonymous}::bytes_in::bits_in::bits_in(const 
> {anonymous}::bytes_in::bits_in&)’
>   735 |   return bits_in (*this);
>   |^
> /src-local/gcc-master/gcc/cp/module.cc:709:3: note: declared here
>   709 |   bits_in(const bits_in&) = delete;
>   |   ^~~
> /src-local/gcc-master/gcc/cp/module.cc: In member function 
> ‘{anonymous}::bytes_out::bits_out {anonymous}::bytes_out::stream_bits()’:
> /src-local/gcc-master/gcc/cp/module.cc:796:25: error: use of deleted function 
> ‘{anonymous}::bytes_out::bits_out::bits_out(const 
> {anonymous}::bytes_out::bits_out&)’
>   796 |   return bits_out (*this);
>   | ^
> /src-local/gcc-master/gcc/cp/module.cc:755:3: note: declared here
>   755 |   bits_out(const bits_out&) = delete;
>   |   ^~~~

Drat, sorry for the breakage.  We need to define defaulted move ctors
for these classes I think.  I'll take care of it ASAP.

Re: [PATCH] c++: problematic assert in reference_binding [PR113141]

2024-04-12 Thread Patrick Palka
On Fri, 12 Apr 2024, Jason Merrill wrote:

> On 3/26/24 09:44, Patrick Palka wrote:
> > On Thu, 7 Mar 2024, Jason Merrill wrote:
> > 
> > > On 1/29/24 17:42, Patrick Palka wrote:
> > > > On Mon, 29 Jan 2024, Patrick Palka wrote:
> > > > 
> > > > > On Fri, 26 Jan 2024, Jason Merrill wrote:
> > > > > 
> > > > > > On 1/26/24 17:11, Jason Merrill wrote:
> > > > > > > On 1/26/24 16:52, Jason Merrill wrote:
> > > > > > > > On 1/25/24 14:18, Patrick Palka wrote:
> > > > > > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this
> > > > > > > > > look
> > > > > > > > > OK for trunk/13?  This isn't a very satisfactory fix, but at
> > > > > > > > > least
> > > > > > > > > it safely fixes these testcases I guess.  Note that there's
> > > > > > > > > implementation disagreement about the second testcase, GCC
> > > > > > > > > always
> > > > > > > > > accepted it but Clang/MSVC/icc reject it.
> > > > > > > > 
> > > > > > > > Because of trying to initialize int& from {c}; removing the
> > > > > > > > extra
> > > > > > > > braces
> > > > > > > > makes it work everywhore.
> > > > > > > > 
> > > > > > > > https://eel.is/c++draft/dcl.init#list-3.10 says that we always
> > > > > > > > generate a
> > > > > > > > prvalue in this case, so perhaps we shouldn't recalculate if the
> > > > > > > > initializer is an init-list?
> > > > > > > 
> > > > > > > ...but it seems bad to silently bind a const int& to a prvalue
> > > > > > > instead
> > > > > > > of
> > > > > > > directly to the reference returned by the operator, as clang does
> > > > > > > if
> > > > > > > we add
> > > > > > > const to the second testcase, so I think there's a defect in the
> > > > > > > standard
> > > > > > > here.
> > > > > > 
> > > > > > Perhaps bullet 3.9 should change to "...its referenced type is
> > > > > > reference-related to E or scalar, ..."
> > > > > > 
> > > > > > > Maybe for now also disable the maybe_valid heuristics in the case
> > > > > > > of
> > > > > > > an
> > > > > > > init-list?
> > > > > > > 
> > > > > > > > The first testcase is special because it's a C-style cast; seems
> > > > > > > > like the
> > > > > > > > maybe_valid = false heuristics should be disabled if c_cast_p.
> > > > > 
> > > > > Thanks a lot for the pointers.  IIUC c_cast_p and
> > > > > LOOKUP_SHORTCUT_BAD_CONVS
> > > > > should already be mutually exclusive, since the latter is set only
> > > > > when
> > > > > computing argument conversions, so it shouldn't be necessary to check
> > > > > c_cast_p.
> > > > > 
> > > > > I suppose we could disable the heuristic for init-lists, but after
> > > > > some
> > > > > digging I noticed that the heuristics were originally in same spot
> > > > > they
> > > > > are now until r5-601-gd02f620dc0bb3b moved them to get checked after
> > > > > the recursive recalculation case in reference_binding, returning a bad
> > > > > conversion instead of NULL.  (Then in r13-1755-g68f37670eff0b872 I
> > > > > moved
> > > > > them back; IIRC that's why I felt confident that moving the checks was
> > > > > safe.)
> > > > > Thus we didn't always accept the second testcase, we only started
> > > > > doing so
> > > > > in
> > > > > GCC 5: https://godbolt.org/z/6nsEW14fh (sorry for missing this and
> > > > > saying
> > > > > we
> > > > > always accepted it)
> > > > > 
> > > > > And indeed the current order of checks seems consistent with that of
> > > > > [dcl.init.ref]/5.  So I wonder if we don't instead want to "complete"
> > > > > the NULL-to

Re: [PATCH] c++/modules: local class merging [PR99426]

2024-04-12 Thread Patrick Palka
On Fri, 12 Apr 2024, Jason Merrill wrote:

> On 4/12/24 13:48, Patrick Palka wrote:
> > On Fri, 12 Apr 2024, Jason Merrill wrote:
> > 
> > > On 4/12/24 10:35, Patrick Palka wrote:
> > > > On Wed, 10 Apr 2024, Jason Merrill wrote:
> > > > 
> > > > > On 4/10/24 14:48, Patrick Palka wrote:
> > > > > > On Tue, 9 Apr 2024, Jason Merrill wrote:
> > > > > > 
> > > > > > > On 3/5/24 10:31, Patrick Palka wrote:
> > > > > > > > On Tue, 27 Feb 2024, Patrick Palka wrote:
> > > > > > > > 
> > > > > > > > Subject: [PATCH] c++/modules: local type merging [PR99426]
> > > > > > > > 
> > > > > > > > One known missing piece in the modules implementation is merging
> > > > > > > > of
> > > > > > > > a
> > > > > > > > streamed-in local type (class or enum) with the corresponding
> > > > > > > > in-TU
> > > > > > > > version of the local type.  This missing piece turns out to
> > > > > > > > cause a
> > > > > > > > hard-to-reduce use-after-free GC issue due to the entity_ary not
> > > > > > > > being
> > > > > > > > marked as a GC root (deliberately), and manifests as a
> > > > > > > > serialization
> > > > > > > > error on stream-in as in PR99426 (see comment #6 for a
> > > > > > > > reduction).
> > > > > > > > It's
> > > > > > > > also reproducible on trunk when running the xtreme-header tests
> > > > > > > > without
> > > > > > > > -fno-module-lazy.
> > > > > > > > 
> > > > > > > > This patch makes us merge such local types according to their
> > > > > > > > position
> > > > > > > > within the containing function's definition, analogous to how we
> > > > > > > > merge
> > > > > > > > FIELD_DECLs of a class according to their index in the
> > > > > > > > TYPE_FIELDS
> > > > > > > > list.
> > > > > > > > 
> > > > > > > > PR c++/99426
> > > > > > > > 
> > > > > > > > gcc/cp/ChangeLog:
> > > > > > > > 
> > > > > > > > * module.cc (merge_kind::MK_local_type): New enumerator.
> > > > > > > > (merge_kind_name): Update.
> > > > > > > > (trees_out::chained_decls): Move BLOCK-specific handling
> > > > > > > > of DECL_LOCAL_DECL_P decls to ...
> > > > > > > > (trees_out::core_vals) : ... here.  Stream
> > > > > > > > BLOCK_VARS manually.
> > > > > > > > (trees_in::core_vals) : Stream BLOCK_VARS
> > > > > > > > manually.  Handle deduplicated local types..
> > > > > > > > (trees_out::key_local_type): Define.
> > > > > > > > (trees_in::key_local_type): Define.
> > > > > > > > (trees_out::get_merge_kind) : Return
> > > > > > > > MK_local_type for a local type.
> > > > > > > > (trees_out::key_mergeable) : Use
> > > > > > > > key_local_type.
> > > > > > > > (trees_in::key_mergeable) : 
> > > > > > > > Likewise.
> > > > > > > > (trees_in::is_matching_decl): Be flexible with type 
> > > > > > > > mismatches
> > > > > > > > for local entities.
> > > > > > > > 
> > > > > > > > diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> > > > > > > > index 80b63a70a62..d9e34e9a4b9 100644
> > > > > > > > --- a/gcc/cp/module.cc
> > > > > > > > +++ b/gcc/cp/module.cc
> > > > > > > > @@ -6714,7 +6720,37 @@ trees_in::core_vals (tree t)
> > > > > > > >  case BLOCK:
> > > > > > > >t->block.locus = state->read_location (*this);
> > > > > > > >t->block.end_locus = state->read_location (*this);
>

Re: [PATCH] c++/modules: local class merging [PR99426]

2024-04-12 Thread Patrick Palka
On Fri, 12 Apr 2024, Jason Merrill wrote:

> On 4/12/24 10:35, Patrick Palka wrote:
> > On Wed, 10 Apr 2024, Jason Merrill wrote:
> > 
> > > On 4/10/24 14:48, Patrick Palka wrote:
> > > > On Tue, 9 Apr 2024, Jason Merrill wrote:
> > > > 
> > > > > On 3/5/24 10:31, Patrick Palka wrote:
> > > > > > On Tue, 27 Feb 2024, Patrick Palka wrote:
> > > > > > 
> > > > > > Subject: [PATCH] c++/modules: local type merging [PR99426]
> > > > > > 
> > > > > > One known missing piece in the modules implementation is merging of
> > > > > > a
> > > > > > streamed-in local type (class or enum) with the corresponding in-TU
> > > > > > version of the local type.  This missing piece turns out to cause a
> > > > > > hard-to-reduce use-after-free GC issue due to the entity_ary not
> > > > > > being
> > > > > > marked as a GC root (deliberately), and manifests as a serialization
> > > > > > error on stream-in as in PR99426 (see comment #6 for a reduction).
> > > > > > It's
> > > > > > also reproducible on trunk when running the xtreme-header tests
> > > > > > without
> > > > > > -fno-module-lazy.
> > > > > > 
> > > > > > This patch makes us merge such local types according to their
> > > > > > position
> > > > > > within the containing function's definition, analogous to how we
> > > > > > merge
> > > > > > FIELD_DECLs of a class according to their index in the TYPE_FIELDS
> > > > > > list.
> > > > > > 
> > > > > > PR c++/99426
> > > > > > 
> > > > > > gcc/cp/ChangeLog:
> > > > > > 
> > > > > > * module.cc (merge_kind::MK_local_type): New enumerator.
> > > > > > (merge_kind_name): Update.
> > > > > > (trees_out::chained_decls): Move BLOCK-specific handling
> > > > > > of DECL_LOCAL_DECL_P decls to ...
> > > > > > (trees_out::core_vals) : ... here.  Stream
> > > > > > BLOCK_VARS manually.
> > > > > > (trees_in::core_vals) : Stream BLOCK_VARS
> > > > > > manually.  Handle deduplicated local types..
> > > > > > (trees_out::key_local_type): Define.
> > > > > > (trees_in::key_local_type): Define.
> > > > > > (trees_out::get_merge_kind) : Return
> > > > > > MK_local_type for a local type.
> > > > > > (trees_out::key_mergeable) : Use
> > > > > > key_local_type.
> > > > > > (trees_in::key_mergeable) : Likewise.
> > > > > > (trees_in::is_matching_decl): Be flexible with type mismatches
> > > > > > for local entities.
> > > > > > 
> > > > > > diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> > > > > > index 80b63a70a62..d9e34e9a4b9 100644
> > > > > > --- a/gcc/cp/module.cc
> > > > > > +++ b/gcc/cp/module.cc
> > > > > > @@ -6714,7 +6720,37 @@ trees_in::core_vals (tree t)
> > > > > > case BLOCK:
> > > > > >   t->block.locus = state->read_location (*this);
> > > > > >   t->block.end_locus = state->read_location (*this);
> > > > > > -  t->block.vars = chained_decls ();
> > > > > > +
> > > > > > +  for (tree *chain = >block.vars;;)
> > > > > > +   if (tree decl = tree_node ())
> > > > > > + {
> > > > > > +   /* For a deduplicated local type or enumerator, chain the
> > > > > > +  duplicate decl instead of the canonical in-TU decl.
> > > > > > Seeing
> > > > > > +  a duplicate here means the containing function whose
> > > > > > body
> > > > > > +  we're streaming in is a duplicate too, so we'll end up
> > > > > > +  discarding this BLOCK (and the rest of the duplicate
> > > > > > function
> > > > > > +  body) anyway.  */
> > > > > > +   if (is_duplicate (decl))
> > > > > > + decl = maybe_duplicate (decl);
> > > > > > +   else if (DECL_I

Re: [PATCH] c++/modules: local class merging [PR99426]

2024-04-12 Thread Patrick Palka
On Wed, 10 Apr 2024, Jason Merrill wrote:

> On 4/10/24 14:48, Patrick Palka wrote:
> > On Tue, 9 Apr 2024, Jason Merrill wrote:
> > 
> > > On 3/5/24 10:31, Patrick Palka wrote:
> > > > On Tue, 27 Feb 2024, Patrick Palka wrote:
> > > > 
> > > > Subject: [PATCH] c++/modules: local type merging [PR99426]
> > > > 
> > > > One known missing piece in the modules implementation is merging of a
> > > > streamed-in local type (class or enum) with the corresponding in-TU
> > > > version of the local type.  This missing piece turns out to cause a
> > > > hard-to-reduce use-after-free GC issue due to the entity_ary not being
> > > > marked as a GC root (deliberately), and manifests as a serialization
> > > > error on stream-in as in PR99426 (see comment #6 for a reduction).  It's
> > > > also reproducible on trunk when running the xtreme-header tests without
> > > > -fno-module-lazy.
> > > > 
> > > > This patch makes us merge such local types according to their position
> > > > within the containing function's definition, analogous to how we merge
> > > > FIELD_DECLs of a class according to their index in the TYPE_FIELDS
> > > > list.
> > > > 
> > > > PR c++/99426
> > > > 
> > > > gcc/cp/ChangeLog:
> > > > 
> > > > * module.cc (merge_kind::MK_local_type): New enumerator.
> > > > (merge_kind_name): Update.
> > > > (trees_out::chained_decls): Move BLOCK-specific handling
> > > > of DECL_LOCAL_DECL_P decls to ...
> > > > (trees_out::core_vals) : ... here.  Stream
> > > > BLOCK_VARS manually.
> > > > (trees_in::core_vals) : Stream BLOCK_VARS
> > > > manually.  Handle deduplicated local types..
> > > > (trees_out::key_local_type): Define.
> > > > (trees_in::key_local_type): Define.
> > > > (trees_out::get_merge_kind) : Return
> > > > MK_local_type for a local type.
> > > > (trees_out::key_mergeable) : Use
> > > > key_local_type.
> > > > (trees_in::key_mergeable) : Likewise.
> > > > (trees_in::is_matching_decl): Be flexible with type mismatches
> > > > for local entities.
> > > > 
> > > > diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> > > > index 80b63a70a62..d9e34e9a4b9 100644
> > > > --- a/gcc/cp/module.cc
> > > > +++ b/gcc/cp/module.cc
> > > > @@ -6714,7 +6720,37 @@ trees_in::core_vals (tree t)
> > > >case BLOCK:
> > > >  t->block.locus = state->read_location (*this);
> > > >  t->block.end_locus = state->read_location (*this);
> > > > -  t->block.vars = chained_decls ();
> > > > +
> > > > +  for (tree *chain = >block.vars;;)
> > > > +   if (tree decl = tree_node ())
> > > > + {
> > > > +   /* For a deduplicated local type or enumerator, chain the
> > > > +  duplicate decl instead of the canonical in-TU decl.  
> > > > Seeing
> > > > +  a duplicate here means the containing function whose body
> > > > +  we're streaming in is a duplicate too, so we'll end up
> > > > +  discarding this BLOCK (and the rest of the duplicate 
> > > > function
> > > > +  body) anyway.  */
> > > > +   if (is_duplicate (decl))
> > > > + decl = maybe_duplicate (decl);
> > > > +   else if (DECL_IMPLICIT_TYPEDEF_P (decl)
> > > > +&& TYPE_TEMPLATE_INFO (TREE_TYPE (decl)))
> > > > + {
> > > > +   tree tmpl = TYPE_TI_TEMPLATE (TREE_TYPE (decl));
> > > > +   if (DECL_TEMPLATE_RESULT (tmpl) == decl && is_duplicate
> > > > (tmpl))
> > > > + decl = DECL_TEMPLATE_RESULT (maybe_duplicate (tmpl));
> > > > + }
> > > 
> > > This seems like a lot of generally-applicable code for finding the
> > > duplicate,
> > > which other calls to maybe_duplicate/odr_duplicate don't use.  If the
> > > template
> > > is a duplicate, why isn't its result?  If there's a good reason for that,
> > > should this template handling go into maybe_duplicate?

Re: [PATCH] c++: templated substitution into lambda-expr [PR114393]

2024-04-12 Thread Patrick Palka
On Wed, 10 Apr 2024, Jason Merrill wrote:

> On 3/27/24 10:01, Patrick Palka wrote:
> > On Mon, 25 Mar 2024, Patrick Palka wrote:
> > > On Mon, 25 Mar 2024, Patrick Palka wrote:
> > > > 
> > > > The below testcases use a lambda-expr as a template argument and they
> > > > all trip over the below added tsubst_lambda_expr sanity check ultimately
> > > > because current_template_parms is empty, which causes push_template_decl
> > > > to return error_mark_node from the call to begin_lambda_type.  Were it
> > > > not for the sanity check this silent error_mark_node result leads to
> > > > nonsensical errors down the line, or silent breakage.
> > > > 
> > > > In the first testcase, we hit this assert during instantiation of the
> > > > dependent alias template-id c1_t<_Data> from instantiate_template, which
> > > > clears current_template_parms via push_to_top_level.  Similar story for
> > > > the second testcase.  For the third testcase we hit the assert during
> > > > partial instantiation of the member template from
> > > > instantiate_class_template
> > > > which similarly calls push_to_top_level.
> > > > 
> > > > These testcases illustrate that templated substitution into a
> > > > lambda-expr
> > > > is not always possible, in particular when we lost the relevant template
> > > > context.  I experimented with recovering the template context by making
> > > > tsubst_lambda_expr fall back to using scope_chain->prev->template_parms
> > > > if
> > > > current_template_parms is empty which worked but seemed like a hack.  I
> > > > also experimented with preserving the template context by keeping
> > > > current_template_parms set during instantiate_template for a dependent
> > > > specialization which also worked but it's at odds with the fact that we
> > > > cache dependent specializations (and so they should be independent of
> > > > the template context).
> 
> I suspect the problem comes from this bit in type_unification_real:
> 
> >   /* First instatiate in template context, in case we still
> > depend on undeduced template parameters.  */
> >   ++processing_template_decl;
> >   substed = tsubst_template_arg (arg, full_targs, complain,
> >  NULL_TREE);
> >   --processing_template_decl;
> >   if (substed != error_mark_node
> >   && !uses_template_parms (substed))
> > /* We replaced all the tparms, substitute again out of
> > template context.  */
> > substed = NULL_TREE;
> 
> and perhaps we should switch to searching the argument for undeduced template
> parameters rather than doing a trial substitution.

Interesting, you also mentioned that approach would help fix PR101463
(which I need to get back to):
https://gcc.gnu.org/pipermail/gcc-patches/2024-January/642340.html

> 
> But the pattern of setting processing_template_decl, substituting, and
> clearing it again is very widespread, so we still want to handle lambdas in
> that context.
> 
> > > > +  if (processing_template_decl && !in_template_context)
> > > > +{
> > > > +  /* Defer templated substitution into a lambda-expr when arguments
> > > > +are dependent or when we lost the necessary template context,
> > > > +which may happen for a lambda-expr used as a template 
> > > > argument.  */
> > > 
> > > And this comment is stale (an earlier version of the patch also deferred
> > > for dependent arguments even when current_template_parms is non-empty,
> > > which I backed out to make the fix as narrow as possible).
> > 
> > FWIW I also experimented with unconditionally deferring templated
> > substitution into a lambda-expr (i.e. iff processing_template_decl)
> > which passed bootstrap+regtest, and turns out to also fix the
> > (non-regression) PR114167.  I didn't analyze the underlying issue
> > very closely though, there might very well be a better way to fix
> > that particular non-regression PR.
> > 
> > One downside of unconditionally deferring is that it'd mean less
> > ahead-of-time checking of uninvoked deeply-nested generic lambdas,
> > e.g.:
> > 
> >int main() {
> >  [](auto x) {
> >[](auto) {
> >  [](auto) { decltype(x)::fail; }; // not d

[PATCH] c++: templated substitution into lambda-expr, cont [PR114393]

2024-04-12 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?

-- >8 --

The original PR114393 testcase is unfortunately still not accepted after
r14-9938-g081c1e93d56d35 due to return type deduction confusion when a
lambda-expr is used as a default template argument.

The below reduced testcase demonstrates the bug.  Here, when forming the
dependent specialization b_v we substitute the default argument of F,
a lambda-expr, with _Descriptor=U.  (In this case in_template_context is
true since we're in the context of the template c_v so we don't defer.)
This substitution in turn lowers the level of its auto return type from
2 to 1.  So later, when instantiating c_v we incorrectly
replace the auto with the template argument at level=0, index=0, i.e.
int, instead of going through do_auto_deduction which would yield char.

One way to fix this would be to use a level-less auto to represent a
deduced return type of a lambda, but that might be too invasive of a
change at this stage.

Another way would be to pass tf_partial during dependent substitution
into a default template argument from coerce_template_parms so that the
levels of deeper parameters don't get lowered, but that wouldn't do
the right thing currently due to the tf_partial early exit in the
LAMBDA_EXPR case of tsubst_expr.

Another way, and the approach that this patch takes, is to just defer
all dependent substitution into a lambda-expr, building upon the logic
added in r14-9938-g081c1e93d56d35.  This seems like the right thing to
do in light of the way we build up LAMBDA_EXPR_REGEN_INFO which should
consist only of the concrete template arguments used to regenerate the
lambda.

PR c++/114393

gcc/cp/ChangeLog:

* pt.cc (tsubst_lambda_expr): Also defer all dependent
substitution into a lambda-expr.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/lambda-targ2a.C: New test.
---
 gcc/cp/pt.cc   |  9 +++--
 gcc/testsuite/g++.dg/cpp2a/lambda-targ2a.C | 14 ++
 2 files changed, 21 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-targ2a.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index ec259ee0fbf..bbd35417f8d 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -19622,11 +19622,16 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
   in_decl = oldfn;
 
   args = add_extra_args (LAMBDA_EXPR_EXTRA_ARGS (t), args, complain, in_decl);
-  if (processing_template_decl && !in_template_context)
+  if (processing_template_decl
+  && (!in_template_context || any_dependent_template_arguments_p (args)))
 {
   /* Defer templated substitution into a lambda-expr if we lost the
 necessary template context.  This may happen for a lambda-expr
-used as a default template argument.  */
+used as a default template argument.
+
+Defer dependent substitution as well so that we don't lower the
+level of a deduced return type or any other auto or template
+parameter.  */
   t = copy_node (t);
   LAMBDA_EXPR_EXTRA_ARGS (t) = NULL_TREE;
   LAMBDA_EXPR_EXTRA_ARGS (t) = build_extra_args (t, args, complain);
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-targ2a.C 
b/gcc/testsuite/g++.dg/cpp2a/lambda-targ2a.C
new file mode 100644
index 000..7136ce79872
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ2a.C
@@ -0,0 +1,14 @@
+// PR c++/114393
+// { dg-do compile { target c++20 } }
+
+template  struct c1 {};
+
+template 
+inline constexpr auto b_v = F;
+
+template 
+inline constexpr auto c_v = b_v;
+
+auto f = c_v;
+using type = decltype(f());
+using type = char;
-- 
2.44.0.568.g436d4e5b14



Re: [PATCH] c++: recalculating local specs via build_extra_args [PR114303]

2024-04-10 Thread Patrick Palka
On Wed, 10 Apr 2024, Jason Merrill wrote:

> On 4/10/24 17:39, Patrick Palka wrote:
> > On Wed, 10 Apr 2024, Jason Merrill wrote:
> > 
> > > On 3/12/24 10:51, Patrick Palka wrote:
> > > > On Tue, 12 Mar 2024, Patrick Palka wrote:
> > > > > On Tue, 12 Mar 2024, Jason Merrill wrote:
> > > > > > On 3/11/24 12:53, Patrick Palka wrote:
> > > > > > > 
> > > > > > > r13-6452-g341e6cd8d603a3 made build_extra_args walk evaluated
> > > > > > > contexts
> > > > > > > first so that we prefer processing a local specialization in an
> > > > > > > evaluated
> > > > > > > context even if its first use is in an unevaluated context.  But
> > > > > > > this
> > > > > > > means we need to avoid walking a tree that already has extra
> > > > > > > args/specs
> > > > > > > saved because the list of saved specs appears to be an evaluated
> > > > > > > context.  It seems then that we should be calculating the saved
> > > > > > > specs
> > > > > > > from scratch each time, rather than potentially walking the saved
> > > > > > > specs
> > > > > > > list from an earlier partial instantiation when calling
> > > > > > > build_extra_args
> > > > > > > a second time around.
> > > > > > 
> > > > > > Makes sense, but I wonder if we want to approach that by avoiding
> > > > > > walking into
> > > > > > *_EXTRA_ARGS in extract_locals_r?  Or do we still want to walk into
> > > > > > any
> > > > > > nested
> > > > > > extra args?  And if so, will we run into this same problem then?
> > > > > 
> > > > > I'm not sure totally but I'd expect a nested extra-args tree to always
> > > > > have empty *_EXTRA_ARGS since the outer extra-args tree should
> > > > > intercept
> > > > > any substitution before the inner extra-args tree can see it?
> > > > 
> > > > ... and so in extract_locals_r I think we can assume *_EXTRA_ARGS is
> > > > empty, and not have to explicitly avoid walking it.
> > > 
> > > It seems more robust to me to handle _EXTRA_ARGS appropriately in
> > > build_extra_args rather than expect callers to know that they shouldn't
> > > pass
> > > in a tree with _EXTRA_ARGS set.  At least check and abort in that case?
> > 
> > Sounds good.  That IMHO seems simpler than actually avoiding walking
> > into *_EXTRA_ARGS from extract_locals_r because we'd have to repeat
> > the walking logic from cp_walk_subtree modulo the *_EXTRA_ARGS walk.
> > 
> > How does the following look? Bootstraped and regtested on
> > x86_64-pc-linux-gnu.
> > 
> > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > index c38594cd862..6cc9b95fc06 100644
> > --- a/gcc/cp/pt.cc
> > +++ b/gcc/cp/pt.cc
> > @@ -13310,6 +13310,19 @@ extract_locals_r (tree *tp, int *walk_subtrees,
> > void *data_)
> >   /* Remember local typedefs (85214).  */
> >   tp = _NAME (*tp);
> >   
> 
> Please add a comment explaining why it needs to be null.
> 
> Also, how about a generic _EXTRA_ARGS accessor so places like this don't need
> to check each code themselves?

Sounds good.

> 
> > +  if (has_extra_args_mechanism_p (*tp))
> > +{
> > +  if (PACK_EXPANSION_P (*tp))
> > +   gcc_checking_assert (!PACK_EXPANSION_EXTRA_ARGS (*tp));
> > +  else if (TREE_CODE (*tp) == REQUIRES_EXPR)
> > +   gcc_checking_assert (!REQUIRES_EXPR_EXTRA_ARGS (*tp));
> > +  else if (TREE_CODE (*tp) == IF_STMT
> > +  && IF_STMT_CONSTEXPR_P (*tp))
> > +   gcc_checking_assert (!IF_STMT_EXTRA_ARGS (*tp));
> > +  else
> > +   gcc_unreachable ();
> > +}
> > +
> > if (TREE_CODE (*tp) == DECL_EXPR)
> >   {
> > tree decl = DECL_EXPR_DECL (*tp);
> > @@ -18738,7 +18751,8 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t
> > complain, tree in_decl)
> >   IF_COND (stmt) = IF_COND (t);
> >   THEN_CLAUSE (stmt) = THEN_CLAUSE (t);
> >   ELSE_CLAUSE (stmt) = ELSE_CLAUSE (t);
> > - IF_STMT_EXTRA_ARGS (stmt) = build_extra_args (t, args, complain);
> > + IF_SCOPE (stmt) = NULL_TREE;
> 
> What does IF_SCOPE have to do with this?

IF_SCOPE is the same field as IF_STMT_EXTRA_ARGS so we need to clear it
before ca

Re: [PATCH] c++: recalculating local specs via build_extra_args [PR114303]

2024-04-10 Thread Patrick Palka
On Wed, 10 Apr 2024, Jason Merrill wrote:

> On 3/12/24 10:51, Patrick Palka wrote:
> > On Tue, 12 Mar 2024, Patrick Palka wrote:
> > > On Tue, 12 Mar 2024, Jason Merrill wrote:
> > > > On 3/11/24 12:53, Patrick Palka wrote:
> > > > > 
> > > > > r13-6452-g341e6cd8d603a3 made build_extra_args walk evaluated contexts
> > > > > first so that we prefer processing a local specialization in an
> > > > > evaluated
> > > > > context even if its first use is in an unevaluated context.  But this
> > > > > means we need to avoid walking a tree that already has extra
> > > > > args/specs
> > > > > saved because the list of saved specs appears to be an evaluated
> > > > > context.  It seems then that we should be calculating the saved specs
> > > > > from scratch each time, rather than potentially walking the saved
> > > > > specs
> > > > > list from an earlier partial instantiation when calling
> > > > > build_extra_args
> > > > > a second time around.
> > > > 
> > > > Makes sense, but I wonder if we want to approach that by avoiding
> > > > walking into
> > > > *_EXTRA_ARGS in extract_locals_r?  Or do we still want to walk into any
> > > > nested
> > > > extra args?  And if so, will we run into this same problem then?
> > > 
> > > I'm not sure totally but I'd expect a nested extra-args tree to always
> > > have empty *_EXTRA_ARGS since the outer extra-args tree should intercept
> > > any substitution before the inner extra-args tree can see it?
> > 
> > ... and so in extract_locals_r I think we can assume *_EXTRA_ARGS is
> > empty, and not have to explicitly avoid walking it.
> 
> It seems more robust to me to handle _EXTRA_ARGS appropriately in
> build_extra_args rather than expect callers to know that they shouldn't pass
> in a tree with _EXTRA_ARGS set.  At least check and abort in that case?

Sounds good.  That IMHO seems simpler than actually avoiding walking
into *_EXTRA_ARGS from extract_locals_r because we'd have to repeat
the walking logic from cp_walk_subtree modulo the *_EXTRA_ARGS walk.

How does the following look? Bootstraped and regtested on
x86_64-pc-linux-gnu.

-- > 8--

Subject: [PATCH] c++: build_extra_args recapturing local specs [PR114303]

PR c++/114303

gcc/cp/ChangeLog:

* constraint.cc (tsubst_requires_expr): Clear
REQUIRES_EXPR_EXTRA_ARGS before calling build_extra_args.
* pt.cc (extract_locals_r): Assert *_EXTRA_ARGS is empty.
(tsubst_stmt) : Call build_extra_args
on the new IF_STMT instead of t which might already have
IF_STMT_EXTRA_ARGS.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/constexpr-if-lambda6.C: New test.
---
 gcc/cp/constraint.cc |  1 +
 gcc/cp/pt.cc | 16 +++-
 .../g++.dg/cpp1z/constexpr-if-lambda6.C  | 16 
 3 files changed, 32 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 49de3211d4c..8a3b5d80ba7 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -2362,6 +2362,7 @@ tsubst_requires_expr (tree t, tree args, sat_info info)
 matching or dguide constraint rewriting), in which case we need
 to partially substitute.  */
   t = copy_node (t);
+  REQUIRES_EXPR_EXTRA_ARGS (t) = NULL_TREE;
   REQUIRES_EXPR_EXTRA_ARGS (t) = build_extra_args (t, args, info.complain);
   return t;
 }
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index c38594cd862..6cc9b95fc06 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -13310,6 +13310,19 @@ extract_locals_r (tree *tp, int *walk_subtrees, void 
*data_)
 /* Remember local typedefs (85214).  */
 tp = _NAME (*tp);
 
+  if (has_extra_args_mechanism_p (*tp))
+{
+  if (PACK_EXPANSION_P (*tp))
+   gcc_checking_assert (!PACK_EXPANSION_EXTRA_ARGS (*tp));
+  else if (TREE_CODE (*tp) == REQUIRES_EXPR)
+   gcc_checking_assert (!REQUIRES_EXPR_EXTRA_ARGS (*tp));
+  else if (TREE_CODE (*tp) == IF_STMT
+  && IF_STMT_CONSTEXPR_P (*tp))
+   gcc_checking_assert (!IF_STMT_EXTRA_ARGS (*tp));
+  else
+   gcc_unreachable ();
+}
+
   if (TREE_CODE (*tp) == DECL_EXPR)
 {
   tree decl = DECL_EXPR_DECL (*tp);
@@ -18738,7 +18751,8 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
  IF_COND (stmt) = IF_COND (t);
  THEN_CLAUSE (stmt) = THEN_CLAUSE (t);
  ELSE_CLAUSE (stmt) = ELSE_CLAUSE (t);
- IF_STMT_EXTRA_ARGS (stmt) = build_extra_args (t, args, complain

Re: [PATCH] c++/modules: local class merging [PR99426]

2024-04-10 Thread Patrick Palka
On Tue, 9 Apr 2024, Jason Merrill wrote:

> On 3/5/24 10:31, Patrick Palka wrote:
> > On Tue, 27 Feb 2024, Patrick Palka wrote:
> > 
> > Subject: [PATCH] c++/modules: local type merging [PR99426]
> > 
> > One known missing piece in the modules implementation is merging of a
> > streamed-in local type (class or enum) with the corresponding in-TU
> > version of the local type.  This missing piece turns out to cause a
> > hard-to-reduce use-after-free GC issue due to the entity_ary not being
> > marked as a GC root (deliberately), and manifests as a serialization
> > error on stream-in as in PR99426 (see comment #6 for a reduction).  It's
> > also reproducible on trunk when running the xtreme-header tests without
> > -fno-module-lazy.
> > 
> > This patch makes us merge such local types according to their position
> > within the containing function's definition, analogous to how we merge
> > FIELD_DECLs of a class according to their index in the TYPE_FIELDS
> > list.
> > 
> > PR c++/99426
> > 
> > gcc/cp/ChangeLog:
> > 
> > * module.cc (merge_kind::MK_local_type): New enumerator.
> > (merge_kind_name): Update.
> > (trees_out::chained_decls): Move BLOCK-specific handling
> > of DECL_LOCAL_DECL_P decls to ...
> > (trees_out::core_vals) : ... here.  Stream
> > BLOCK_VARS manually.
> > (trees_in::core_vals) : Stream BLOCK_VARS
> > manually.  Handle deduplicated local types..
> > (trees_out::key_local_type): Define.
> > (trees_in::key_local_type): Define.
> > (trees_out::get_merge_kind) : Return
> > MK_local_type for a local type.
> > (trees_out::key_mergeable) : Use
> > key_local_type.
> > (trees_in::key_mergeable) : Likewise.
> > (trees_in::is_matching_decl): Be flexible with type mismatches
> > for local entities.
> > 
> > diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> > index 80b63a70a62..d9e34e9a4b9 100644
> > --- a/gcc/cp/module.cc
> > +++ b/gcc/cp/module.cc
> > @@ -6714,7 +6720,37 @@ trees_in::core_vals (tree t)
> >   case BLOCK:
> > t->block.locus = state->read_location (*this);
> > t->block.end_locus = state->read_location (*this);
> > -  t->block.vars = chained_decls ();
> > +
> > +  for (tree *chain = >block.vars;;)
> > +   if (tree decl = tree_node ())
> > + {
> > +   /* For a deduplicated local type or enumerator, chain the
> > +  duplicate decl instead of the canonical in-TU decl.  Seeing
> > +  a duplicate here means the containing function whose body
> > +  we're streaming in is a duplicate too, so we'll end up
> > +  discarding this BLOCK (and the rest of the duplicate function
> > +  body) anyway.  */
> > +   if (is_duplicate (decl))
> > + decl = maybe_duplicate (decl);
> > +   else if (DECL_IMPLICIT_TYPEDEF_P (decl)
> > +&& TYPE_TEMPLATE_INFO (TREE_TYPE (decl)))
> > + {
> > +   tree tmpl = TYPE_TI_TEMPLATE (TREE_TYPE (decl));
> > +   if (DECL_TEMPLATE_RESULT (tmpl) == decl && is_duplicate
> > (tmpl))
> > + decl = DECL_TEMPLATE_RESULT (maybe_duplicate (tmpl));
> > + }
> 
> This seems like a lot of generally-applicable code for finding the duplicate,
> which other calls to maybe_duplicate/odr_duplicate don't use.  If the template
> is a duplicate, why isn't its result?  If there's a good reason for that,
> should this template handling go into maybe_duplicate?

Ah yeah, that makes sense.

Some context: IIUC modules treats the TEMPLATE_DECL instead of the
DECL_TEMPLATE_RESULT as the canonical decl, which in turn means we'll
register_duplicate only the TEMPLATE_DECL.  But BLOCK_VARS never contains
a TEMPLATE_DECL, always the DECL_TEMPLATE_RESULT (i.e. a TYPE_DECL),
hence the extra handling.

Given that it's relatively more difficult to get at the TEMPLATE_DECL
from the DECL_TEMPLATE_RESULT rather than vice versa, maybe we should
just register both as duplicates from register_duplicate?  That way
callers can just simply pass the DECL_TEMPLATE_RESULT to maybe_duplicate
and it'll do the right thing.

> 
> > @@ -10337,6 +10373,83 @@ trees_in::fn_parms_fini (int tag, tree fn, tree
> > existing, bool is_defn)
> >   }
> >   }
> >   +/* Encode into KEY the position of the local type (class or enum)
> > +   declaration DECL within FN.  The position is encoded as the
> > +   index of the innermost BLOCK (numbered in BFS order) along with
> > +   the index within i

Re: [PATCH] c++/modules: optimize tree flag streaming

2024-04-10 Thread Patrick Palka
On Wed, 10 Apr 2024, Patrick Palka wrote:

> 
> On Tue, 9 Apr 2024, Jason Merrill wrote:
> 
> > On 2/16/24 10:06, Patrick Palka wrote:
> > > On Thu, 15 Feb 2024, Patrick Palka wrote:
> > > 
> > > > One would expect consecutive calls to bytes_in/out::b for streaming
> > > > adjacent bits, as we do for tree flag streaming, to at least be
> > > > optimized by the compiler into individual bit operations using
> > > > statically known bit positions (and ideally merged into larger sized
> > > > reads/writes).
> > 
> > Did you have any thoughts about how feasible it would be to use
> > data-streamer.h?  I didn't see a response to richi's mail.
> 
> IIUC the workhorses of data-streamer.h are
> 
>   for streaming out: bitpack_create / bp_pack_value / streamer_write_bitpack
>   for streaming in:  streamer_read_bitpack / bp_unpack_value
> 
> which use a locally constructed bitpack_d struct for state management,
> much like what this patch proposes, which is a sign that this is a good
> approach I suppose.
> 
> The bit twiddling code is unsurprisingly pretty similar except
> data-streamer.h can stream more than one bit at a time whereas
> bits_in/out::b from this patch can only handle one bit at a time
> (which is by far the common case).  Another difference is that the
> data-streamer.h buffer is a HOST_WIDE_INT while the modules bit buffer
> is uint32_t (this patch doesn't change that).
> 
> Unfortunately it seems data-streamer.h is currently hardcoded for
> LTO streaming since bitpack_d::stream must be an lto_input_block and it
> uses streamer_write_uhwi_stream and streamer_read_uhwi under the hood.
> So we can't use it for modules streaming currently without abstracting
> away this hardcoding AFAICT.
> 
> > 
> > > > Unfortunately this doesn't happen because the compiler has trouble
> > > > tracking the values of this->bit_pos and this->bit_val across such
> > > > calls, likely because the compiler doesn't know 'this' and so it's
> > > > treated as global memory.  This means for each consecutive bit stream
> > > > operation, bit_pos and bit_val are loaded from memory, checked if
> > > > buffering is needed, and finally the bit is extracted from bit_val
> > > > according to the (unknown) bit_pos, even though relative to the previous
> > > > operation (if we didn't need to buffer) bit_val is unchanged and bit_pos
> > > > is just 1 larger.  This ends up being quite slow, with tree_node_bools
> > > > taking 10% of time when streaming in parts of the std module.
> > > > 
> > > > This patch optimizes this by making tracking of bit_pos and bit_val
> > > > easier for the compiler.  Rather than bit_pos and bit_val being members
> > > > of the (effectively global) bytes_in/out objects, this patch factors out
> > > > the bit streaming code/state into separate classes bits_in/out that get
> > > > constructed locally as needed for bit streaming.  Since these objects
> > > > are now clearly local, the compiler can more easily track their values.
> > 
> > Please add this rationale to the bits_in comment.
> 
> Will do.
> 
> > 
> > > > And since bit streaming is intended to be batched it's natural for these
> > > > new classes to be RAII-enabled such that the bit stream is flushed upon
> > > > destruction.
> > > > 
> > > > In order to make the most of this improved tracking of bit position,
> > > > this patch changes parts where we conditionally stream a tree flag
> > > > to unconditionally stream (the flag or a dummy value).  That way
> > > > the number of bits streamed and the respective bit positions are as
> > > > statically known as reasonably possible.  In lang_decl_bools and
> > > > lang_type_bools we flush the current bit buffer at the start so that
> > > > subsequent bit positions are statically known.  And in core bools, we
> > > > can add explicit early exits utilizing invariants that the compiler
> > > > can't figure out itself (e.g. a tree code can't have both TS_TYPE_COMMON
> > > > and TS_DECL_COMMON, and if a tree code doesn't have TS_DECL_COMMON then
> > > > it doesn't have TS_DECL_WITH_VIS).  Finally if we're streaming fewer
> > > > than 4 bits, it's more space efficient to stream them as individual
> > > > bytes rather than as packed bits (due to the 32-bit buffer).
> > > 
> > > Oops, this last sentence is wrong.  Although the size of the bit buffer
> > > is 32 bits,

Re: [PATCH] c++/modules: optimize tree flag streaming

2024-04-10 Thread Patrick Palka


On Tue, 9 Apr 2024, Jason Merrill wrote:

> On 2/16/24 10:06, Patrick Palka wrote:
> > On Thu, 15 Feb 2024, Patrick Palka wrote:
> > 
> > > One would expect consecutive calls to bytes_in/out::b for streaming
> > > adjacent bits, as we do for tree flag streaming, to at least be
> > > optimized by the compiler into individual bit operations using
> > > statically known bit positions (and ideally merged into larger sized
> > > reads/writes).
> 
> Did you have any thoughts about how feasible it would be to use
> data-streamer.h?  I didn't see a response to richi's mail.

IIUC the workhorses of data-streamer.h are

  for streaming out: bitpack_create / bp_pack_value / streamer_write_bitpack
  for streaming in:  streamer_read_bitpack / bp_unpack_value

which use a locally constructed bitpack_d struct for state management,
much like what this patch proposes, which is a sign that this is a good
approach I suppose.

The bit twiddling code is unsurprisingly pretty similar except
data-streamer.h can stream more than one bit at a time whereas
bits_in/out::b from this patch can only handle one bit at a time
(which is by far the common case).  Another difference is that the
data-streamer.h buffer is a HOST_WIDE_INT while the modules bit buffer
is uint32_t (this patch doesn't change that).

Unfortunately it seems data-streamer.h is currently hardcoded for
LTO streaming since bitpack_d::stream must be an lto_input_block and it
uses streamer_write_uhwi_stream and streamer_read_uhwi under the hood.
So we can't use it for modules streaming currently without abstracting
away this hardcoding AFAICT.

> 
> > > Unfortunately this doesn't happen because the compiler has trouble
> > > tracking the values of this->bit_pos and this->bit_val across such
> > > calls, likely because the compiler doesn't know 'this' and so it's
> > > treated as global memory.  This means for each consecutive bit stream
> > > operation, bit_pos and bit_val are loaded from memory, checked if
> > > buffering is needed, and finally the bit is extracted from bit_val
> > > according to the (unknown) bit_pos, even though relative to the previous
> > > operation (if we didn't need to buffer) bit_val is unchanged and bit_pos
> > > is just 1 larger.  This ends up being quite slow, with tree_node_bools
> > > taking 10% of time when streaming in parts of the std module.
> > > 
> > > This patch optimizes this by making tracking of bit_pos and bit_val
> > > easier for the compiler.  Rather than bit_pos and bit_val being members
> > > of the (effectively global) bytes_in/out objects, this patch factors out
> > > the bit streaming code/state into separate classes bits_in/out that get
> > > constructed locally as needed for bit streaming.  Since these objects
> > > are now clearly local, the compiler can more easily track their values.
> 
> Please add this rationale to the bits_in comment.

Will do.

> 
> > > And since bit streaming is intended to be batched it's natural for these
> > > new classes to be RAII-enabled such that the bit stream is flushed upon
> > > destruction.
> > > 
> > > In order to make the most of this improved tracking of bit position,
> > > this patch changes parts where we conditionally stream a tree flag
> > > to unconditionally stream (the flag or a dummy value).  That way
> > > the number of bits streamed and the respective bit positions are as
> > > statically known as reasonably possible.  In lang_decl_bools and
> > > lang_type_bools we flush the current bit buffer at the start so that
> > > subsequent bit positions are statically known.  And in core bools, we
> > > can add explicit early exits utilizing invariants that the compiler
> > > can't figure out itself (e.g. a tree code can't have both TS_TYPE_COMMON
> > > and TS_DECL_COMMON, and if a tree code doesn't have TS_DECL_COMMON then
> > > it doesn't have TS_DECL_WITH_VIS).  Finally if we're streaming fewer
> > > than 4 bits, it's more space efficient to stream them as individual
> > > bytes rather than as packed bits (due to the 32-bit buffer).
> > 
> > Oops, this last sentence is wrong.  Although the size of the bit buffer
> > is 32 bits, upon flushing we rewind unused bytes within the buffer,
> > which means streaming 2-8 bits ends up using only one byte not all four.
> > So v2 below undoes this pessimization.
> > 
> > > This patch also moves the definitions of the relevant streaming classes
> > > into anonymous namespaces so that the compiler can make more informed
> > > decisions about inlining their member functions.
> 
> I'm 

Re: [PATCH] c++/modules: optimize tree flag streaming

2024-04-09 Thread Patrick Palka
On Tue, 26 Mar 2024, Patrick Palka wrote:

> On Tue, 27 Feb 2024, Patrick Palka wrote:
> 
> > On Fri, 16 Feb 2024, Patrick Palka wrote:
> > 
> > > On Thu, 15 Feb 2024, Patrick Palka wrote:
> > > 
> > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> > > > OK for trunk?
> > > > 
> > > > -- >8 --
> > > > 
> > > > One would expect consecutive calls to bytes_in/out::b for streaming
> > > > adjacent bits, as we do for tree flag streaming, to at least be
> > > > optimized by the compiler into individual bit operations using
> > > > statically known bit positions (and ideally merged into larger sized
> > > > reads/writes).
> > > > 
> > > > Unfortunately this doesn't happen because the compiler has trouble
> > > > tracking the values of this->bit_pos and this->bit_val across such
> > > > calls, likely because the compiler doesn't know 'this' and so it's
> > > > treated as global memory.  This means for each consecutive bit stream
> > > > operation, bit_pos and bit_val are loaded from memory, checked if
> > > > buffering is needed, and finally the bit is extracted from bit_val
> > > > according to the (unknown) bit_pos, even though relative to the previous
> > > > operation (if we didn't need to buffer) bit_val is unchanged and bit_pos
> > > > is just 1 larger.  This ends up being quite slow, with tree_node_bools
> > > > taking 10% of time when streaming in parts of the std module.
> > > > 
> > > > This patch optimizes this by making tracking of bit_pos and bit_val
> > > > easier for the compiler.  Rather than bit_pos and bit_val being members
> > > > of the (effectively global) bytes_in/out objects, this patch factors out
> > > > the bit streaming code/state into separate classes bits_in/out that get
> > > > constructed locally as needed for bit streaming.  Since these objects
> > > > are now clearly local, the compiler can more easily track their values.
> > > > 
> > > > And since bit streaming is intended to be batched it's natural for these
> > > > new classes to be RAII-enabled such that the bit stream is flushed upon
> > > > destruction.
> > > > 
> > > > In order to make the most of this improved tracking of bit position,
> > > > this patch changes parts where we conditionally stream a tree flag
> > > > to unconditionally stream (the flag or a dummy value).  That way
> > > > the number of bits streamed and the respective bit positions are as
> > > > statically known as reasonably possible.  In lang_decl_bools and
> > > > lang_type_bools we flush the current bit buffer at the start so that
> > > > subsequent bit positions are statically known.  And in core bools, we
> > > > can add explicit early exits utilizing invariants that the compiler
> > > > can't figure out itself (e.g. a tree code can't have both TS_TYPE_COMMON
> > > > and TS_DECL_COMMON, and if a tree code doesn't have TS_DECL_COMMON then
> > > > it doesn't have TS_DECL_WITH_VIS).  Finally if we're streaming fewer
> > > > than 4 bits, it's more space efficient to stream them as individual
> > > > bytes rather than as packed bits (due to the 32-bit buffer).
> > > 
> > > Oops, this last sentence is wrong.  Although the size of the bit buffer
> > > is 32 bits, upon flushing we rewind unused bytes within the buffer,
> > > which means streaming 2-8 bits ends up using only one byte not all four.
> > > So v2 below undoes this pessimization.
> > > 
> > > > This patch also moves the definitions of the relevant streaming classes
> > > > into anonymous namespaces so that the compiler can make more informed
> > > > decisions about inlining their member functions.
> > > > 
> > > > After this patch, compile time for a simple Hello World using the std
> > > > module is reduced by 7% with a release compiler.  The on-disk size of
> > > > the std module increases by 0.7% (presumably due to the extra flushing
> > > > done in lang_decl_bools and lang_type_bools).
> > > 
> > > The on-disk std module now only grows 0.4% instead of 0.7%.
> > > 
> > > > 
> > > > The bit stream out performance isn't improved as much as the stream in
> > > > due to the spans/lengths instrumentation performed on stream out (which
> > > > probably should be e.g. rem

Re: [PATCH] c++/modules: local class merging [PR99426]

2024-04-09 Thread Patrick Palka
On Tue, 26 Mar 2024, Patrick Palka wrote:

> On Tue, 5 Mar 2024, Patrick Palka wrote:
> 
> > On Tue, 27 Feb 2024, Patrick Palka wrote:
> > 
> > > On Mon, 26 Feb 2024, Patrick Palka wrote:
> > > 
> > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this approach
> > > > look reasonable?
> > > > 
> > > > -- >8 --
> > > > 
> > > > One known missing piece in the modules implementation is merging of a
> > > > streamed-in local class with the corresponding in-TU version of the
> > > > local class.  This missing piece turns out to cause a hard-to-reduce
> > > > use-after-free GC issue due to the entity_ary not being marked as a GC
> > > > root (deliberately), and manifests as a serialization error on stream-in
> > > > as in PR99426 (see comment #6 for a reduction).  It's also reproducible
> > > > on trunk when running the xtreme-header tests without -fno-module-lazy.
> > > > 
> > > > This patch makes us merge such local classes according to their position
> > > > within the containing function's definition, similar to how we merge
> > > > FIELD_DECLs of a class according to their index in the TYPE_FIELDS
> > > > list.
> > > > 
> > > > PR c++/99426
> > > > 
> > > > gcc/cp/ChangeLog:
> > > > 
> > > > * module.cc (merge_kind::MK_local_class): New enumerator.
> > > > (merge_kind_name): Update.
> > > > (trees_out::chained_decls): Move BLOCK-specific handling
> > > > of DECL_LOCAL_DECL_P decls to ...
> > > > (trees_out::core_vals) : ... here.  Stream
> > > > BLOCK_VARS manually.
> > > > (trees_in::core_vals) : Stream BLOCK_VARS
> > > > manually.  Handle deduplicated local classes.
> > > > (trees_out::key_local_class): Define.
> > > > (trees_in::key_local_class): Define.
> > > > (trees_out::get_merge_kind) : Return
> > > > MK_local_class for a local class.
> > > > (trees_out::key_mergeable) : Use
> > > > key_local_class.
> > > > (trees_in::key_mergeable) : Likewise.
> > > > (trees_in::is_matching_decl): Be flexible with type mismatches
> > > > for local entities.
> > > > 
> > > > gcc/testsuite/ChangeLog:
> > > > 
> > > > * g++.dg/modules/xtreme-header-7_a.H: New test.
> > > > * g++.dg/modules/xtreme-header-7_b.C: New test.
> > > 
> > > > ---
> > > >  gcc/cp/module.cc  | 167 +++---
> > > >  .../g++.dg/modules/xtreme-header-7_a.H|   4 +
> > > >  .../g++.dg/modules/xtreme-header-7_b.C|   6 +
> > > >  3 files changed, 149 insertions(+), 28 deletions(-)
> > > >  create mode 100644 gcc/testsuite/g++.dg/modules/xtreme-header-7_a.H
> > > >  create mode 100644 gcc/testsuite/g++.dg/modules/xtreme-header-7_b.C
> > > > 
> > > > diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> > > > index fa91c6ff9cb..f77f73a59ed 100644
> > > > --- a/gcc/cp/module.cc
> > > > +++ b/gcc/cp/module.cc
> > > > @@ -2771,6 +2771,7 @@ enum merge_kind
> > > >  
> > > >MK_enum, /* Found by CTX, & 1stMemberNAME.  */
> > > >MK_keyed, /* Found by key & index.  */
> > > > +  MK_local_class, /* Found by CTX, index.  */
> > > >  
> > > >MK_friend_spec,  /* Like named, but has a tmpl & args too.  */
> > > >MK_local_friend, /* Found by CTX, index.  */
> > > > @@ -2799,7 +2800,7 @@ static char const *const merge_kind_name[MK_hwm] =
> > > >  "unique", "named", "field", "vtable",  /* 0...3  */
> > > >  "asbase", "partial", "enum", "attached",   /* 4...7  */
> > > >  
> > > > -"friend spec", "local friend", NULL, NULL,  /* 8...11 */
> > > > +"local class", "friend spec", "local friend", NULL,  /* 8...11 */
> > > >  NULL, NULL, NULL, NULL,
> > > >  
> > > >  "type spec", "type tmpl spec", /* 16,17 type (template).  */
> > > > @@ -2928,6 +2929,7 @@ public:
> > > >unsigned binfo_mergeable (tree *)

Re: [PATCH] c++: recalculating local specs via build_extra_args [PR114303]

2024-04-09 Thread Patrick Palka
On Tue, 26 Mar 2024, Patrick Palka wrote:

> On Mon, 11 Mar 2024, Patrick Palka wrote:
> 
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> > OK for trunk and release branches?
> 
> Ping.

Ping.

> 
> > 
> > -- >8 --
> > 
> > r13-6452-g341e6cd8d603a3 made build_extra_args walk evaluated contexts
> > first so that we prefer processing a local specialization in an evaluated
> > context even if its first use is in an unevaluated context.  But this
> > means we need to avoid walking a tree that already has extra args/specs
> > saved because the list of saved specs appears to be an evaluated
> > context.  It seems then that we should be calculating the saved specs
> > from scratch each time, rather than potentially walking the saved specs
> > list from an earlier partial instantiation when calling build_extra_args
> > a second time around.
> > 
> > PR c++/114303
> > 
> > gcc/cp/ChangeLog:
> > 
> > * constraint.cc (tsubst_requires_expr): Clear
> > REQUIRES_EXPR_EXTRA_ARGS before calling build_extra_args.
> > * pt.cc (tsubst_stmt) : Call build_extra_args
> > on the new IF_STMT instead of t which might already have
> > IF_STMT_EXTRA_ARGS.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/cpp1z/constexpr-if-lambda6.C: New test.
> > ---
> >  gcc/cp/constraint.cc |  1 +
> >  gcc/cp/pt.cc |  2 +-
> >  .../g++.dg/cpp1z/constexpr-if-lambda6.C  | 16 
> >  3 files changed, 18 insertions(+), 1 deletion(-)
> >  create mode 100644 gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C
> > 
> > diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> > index 49de3211d4c..8a3b5d80ba7 100644
> > --- a/gcc/cp/constraint.cc
> > +++ b/gcc/cp/constraint.cc
> > @@ -2362,6 +2362,7 @@ tsubst_requires_expr (tree t, tree args, sat_info 
> > info)
> >  matching or dguide constraint rewriting), in which case we need
> >  to partially substitute.  */
> >t = copy_node (t);
> > +  REQUIRES_EXPR_EXTRA_ARGS (t) = NULL_TREE;
> >REQUIRES_EXPR_EXTRA_ARGS (t) = build_extra_args (t, args, 
> > info.complain);
> >return t;
> >  }
> > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > index 8cf0d5b7a8d..37f2392d035 100644
> > --- a/gcc/cp/pt.cc
> > +++ b/gcc/cp/pt.cc
> > @@ -18718,7 +18718,7 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t 
> > complain, tree in_decl)
> >   IF_COND (stmt) = IF_COND (t);
> >   THEN_CLAUSE (stmt) = THEN_CLAUSE (t);
> >   ELSE_CLAUSE (stmt) = ELSE_CLAUSE (t);
> > - IF_STMT_EXTRA_ARGS (stmt) = build_extra_args (t, args, complain);
> > + IF_STMT_EXTRA_ARGS (stmt) = build_extra_args (stmt, args, complain);
> >   add_stmt (stmt);
> >   break;
> > }
> > diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C 
> > b/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C
> > new file mode 100644
> > index 000..038c2a41210
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C
> > @@ -0,0 +1,16 @@
> > +// PR c++/114303
> > +// { dg-do compile { target c++17 } }
> > +
> > +struct A { static constexpr bool value = true; };
> > +
> > +int main() {
> > +  [](auto x1) {
> > +return [&](auto) {
> > +  return [&](auto x3) {
> > +if constexpr (decltype(x3)::value) {
> > +  static_assert(decltype(x1)::value);
> > +}
> > +  }(A{});
> > +}(0);
> > +  }(A{});
> > +}
> > -- 
> > 2.44.0.165.ge09f1254c5
> > 
> > 
> 



Re: [PATCH] c++: templated substitution into lambda-expr [PR114393]

2024-04-09 Thread Patrick Palka
On Wed, 27 Mar 2024, Patrick Palka wrote:

> On Mon, 25 Mar 2024, Patrick Palka wrote:
> 
> > On Mon, 25 Mar 2024, Patrick Palka wrote:
> > 
> > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
> > > for trunk?
> > > 
> > > -- >8 --
> > > 
> > > The below testcases use a lambda-expr as a template argument and they
> > > all trip over the below added tsubst_lambda_expr sanity check ultimately
> > > because current_template_parms is empty, which causes push_template_decl
> > > to return error_mark_node from the call to begin_lambda_type.  Were it
> > > not for the sanity check this silent error_mark_node result leads to
> > > nonsensical errors down the line, or silent breakage.
> > > 
> > > In the first testcase, we hit this assert during instantiation of the
> > > dependent alias template-id c1_t<_Data> from instantiate_template, which
> > > clears current_template_parms via push_to_top_level.  Similar story for
> > > the second testcase.  For the third testcase we hit the assert during
> > > partial instantiation of the member template from 
> > > instantiate_class_template
> > > which similarly calls push_to_top_level.
> > > 
> > > These testcases illustrate that templated substitution into a lambda-expr
> > > is not always possible, in particular when we lost the relevant template
> > > context.  I experimented with recovering the template context by making
> > > tsubst_lambda_expr fall back to using scope_chain->prev->template_parms if
> > > current_template_parms is empty which worked but seemed like a hack.  I
> > > also experimented with preserving the template context by keeping
> > > current_template_parms set during instantiate_template for a dependent
> > > specialization which also worked but it's at odds with the fact that we
> > > cache dependent specializations (and so they should be independent of
> > > the template context).
> > > 
> > > So instead of trying to make such substitution work, this patch uses the
> > > extra-args mechanism to defer templated substitution into a lambda-expr
> > > when we lost the relevant template context.
> > > 
> > >   PR c++/114393
> > >   PR c++/107457
> > >   PR c++/93595
> > > 
> > > gcc/cp/ChangeLog:
> > > 
> > >   * cp-tree.h (LAMBDA_EXPR_EXTRA_ARGS):
> > >   (struct GTY):
> > >   * module.cc (trees_out::core_vals) : Stream
> > >   LAMBDA_EXPR_EXTRA_ARGS.
> > >   (trees_in::core_vals) : Likewise.
> > >   * pt.cc (has_extra_args_mechanism_p):
> > >   (tsubst_lambda_expr):
> > 
> > Whoops, this version of the patch has an incomplete ChangeLog entry.
> > 
> > > 
> > > gcc/testsuite/ChangeLog:
> > > 
> > >   * g++.dg/cpp2a/lambda-targ2.C: New test.
> > >   * g++.dg/cpp2a/lambda-targ3.C: New test.
> > >   * g++.dg/cpp2a/lambda-targ4.C: New test.
> > > ---
> > >  gcc/cp/cp-tree.h  |  5 +
> > >  gcc/cp/module.cc  |  2 ++
> > >  gcc/cp/pt.cc  | 20 ++--
> > >  gcc/testsuite/g++.dg/cpp2a/lambda-targ2.C | 19 +++
> > >  gcc/testsuite/g++.dg/cpp2a/lambda-targ3.C | 12 
> > >  gcc/testsuite/g++.dg/cpp2a/lambda-targ4.C | 12 
> > >  6 files changed, 68 insertions(+), 2 deletions(-)
> > >  create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-targ2.C
> > >  create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-targ3.C
> > >  create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-targ4.C
> > > 
> > > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> > > index c29a5434492..27100537038 100644
> > > --- a/gcc/cp/cp-tree.h
> > > +++ b/gcc/cp/cp-tree.h
> > > @@ -1538,6 +1538,10 @@ enum cp_lambda_default_capture_mode_type {
> > >  #define LAMBDA_EXPR_REGEN_INFO(NODE) \
> > >(((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->regen_info)
> > >  
> > > +/* Like PACK_EXPANSION_EXTRA_ARGS, for lambda-expressions.  */
> > > +#define LAMBDA_EXPR_EXTRA_ARGS(NODE) \
> > > +  (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->extra_args)
> > > +
> > >  /* The closure type of the lambda, which is also the type of the
> > > LAMBDA_EXPR.  */
> > >  #define LAMBDA_EXPR_CLOSURE(NODE) \
> > > @@ -1550,6 +1554,7 @@ struct GTY (()) tree_lambda_

Re: [PATCH] c++: print source code in print_instantiation_partial_context_line

2024-04-09 Thread Patrick Palka
On Thu, 19 Oct 2023, Patrick Palka wrote:

> On Tue, 3 Oct 2023, David Malcolm wrote:
> 
> > As mentioned in my Cauldron talk, this patch adds a call to
> > diagnostic_show_locus to the "required from here" messages
> > in print_instantiation_partial_context_line, so that e.g., rather
> > than the rather mystifying:
> > 
> > In file included from ../x86_64-pc-linux-gnu/libstdc++-v3/include/memory:78,
> >  from ../../src/demo-1.C:1:
> > ../x86_64-pc-linux-gnu/libstdc++-v3/include/bits/unique_ptr.h: In 
> > instantiation of ‘std::__detail::__unique_ptr_t<_Tp> 
> > std::make_unique(_Args&& ...) [with _Tp = bar; _Args = {}; 
> > __detail::__unique_ptr_t<_Tp> = __detail::__unique_ptr_t]’:
> > ../../src/demo-1.C:15:32:   required from here
> > ../x86_64-pc-linux-gnu/libstdc++-v3/include/bits/unique_ptr.h:1066:30: 
> > error: no matching function for call to ‘bar::bar()’
> >  1066 | { return unique_ptr<_Tp>(new 
> > _Tp(std::forward<_Args>(__args)...)); }
> >   |  ^~~
> > ../../src/demo-1.C:10:3: note: candidate: ‘bar::bar(int)’
> >10 |   bar (int);
> >   |   ^~~
> > ../../src/demo-1.C:10:3: note:   candidate expects 1 argument, 0 provided
> > ../../src/demo-1.C:7:7: note: candidate: ‘constexpr bar::bar(const bar&)’
> > 7 | class bar : public foo
> >   |   ^~~
> > ../../src/demo-1.C:7:7: note:   candidate expects 1 argument, 0 provided
> > ../../src/demo-1.C:7:7: note: candidate: ‘constexpr bar::bar(bar&&)’
> > ../../src/demo-1.C:7:7: note:   candidate expects 1 argument, 0 provided
> > 
> > we emit:
> > 
> > In file included from ../x86_64-pc-linux-gnu/libstdc++-v3/include/memory:78,
> >  from ../../src/demo-1.C:1:
> > ../x86_64-pc-linux-gnu/libstdc++-v3/include/bits/unique_ptr.h: In 
> > instantiation of ‘std::__detail::__unique_ptr_t<_Tp> 
> > std::make_unique(_Args&& ...) [with _Tp = bar; _Args = {}; 
> > __detail::__unique_ptr_t<_Tp> = __detail::__unique_ptr_t]’:
> > ../../src/demo-1.C:15:32:   required from here
> >15 |   return std::make_unique ();
> >   |  ~~^~
> > ../x86_64-pc-linux-gnu/libstdc++-v3/include/bits/unique_ptr.h:1066:30: 
> > error: no matching function for call to ‘bar::bar()’
> >  1066 | { return unique_ptr<_Tp>(new 
> > _Tp(std::forward<_Args>(__args)...)); }
> >   |  ^~~
> > ../../src/demo-1.C:10:3: note: candidate: ‘bar::bar(int)’
> >10 |   bar (int);
> >   |   ^~~
> > ../../src/demo-1.C:10:3: note:   candidate expects 1 argument, 0 provided
> > ../../src/demo-1.C:7:7: note: candidate: ‘constexpr bar::bar(const bar&)’
> > 7 | class bar : public foo
> >   |   ^~~
> > ../../src/demo-1.C:7:7: note:   candidate expects 1 argument, 0 provided
> > ../../src/demo-1.C:7:7: note: candidate: ‘constexpr bar::bar(bar&&)’
> > ../../src/demo-1.C:7:7: note:   candidate expects 1 argument, 0 provided
> > 
> > which shows the code that's leading to the error (the bad call to
> > std::make_unique).
> 
> This is great!  I noticed however that the source code gets printed in a
> surprising way in some contexts.  Consider:
> 
> template void f(typename T::type);
> 
> int main() {
>   f(0);
> }
> 
> For this testcase we emit:
> 
> testcase.C: In function ‘int main()’:
> testcase.C:4:9: error: no matching function for call to ‘f(int)’
> 4 |   f(0);
>   |   ~~^~~
> testcase.C:1:24: note: candidate: ‘template void f(typename T::type)’
> 1 | template void f(typename T::type);
>   |^
> testcase.C:1:24: note:   template argument deduction/substitution failed:
> testcase.C: In substitution of ‘template void f(typename T::type) 
> [with T = int]’:
> testcase.C:4:9:   required from here
> testcase.C:1:24: note: 4 |   f(0);
> testcase.C:1:24: note:   |   ~~^~~
> testcase.C:1:24: error: ‘int’ is not a class, struct, or union type
> 1 | template void f(typename T::type);
>   |^
> 
> In particular the source code part following the "required from here" line
> 
> testcase.C:4:9:   required from here
> testcase.C:1:24: note: 4 |   f(0);
> testcase.C:1:24: note:   |   ~~^~~
> 
> seems off, I would have expected it be
> 
> testcase.C:4:9:   required from here
> 4 |   f(0);
>   |   ~~^~~
> 
&

Re: [PATCH] libstdc++: Allow adjacent __maybe_present_t to overlap

2024-04-02 Thread Patrick Palka
On Tue, 2 Apr 2024, Jonathan Wakely wrote:

> On Tue, 2 Apr 2024 at 18:00, Pilar Latiesa wrote:
> >
> > Just out of curiosity: would this also work?
> >
> > template
> > struct _Absent {};
> >
> > template
> > using __maybe_present_t = __conditional_t<_Present, _Tp, _Absent<_Tp, 
> > _Disc>>;
> >
> > That would avoid having to type 0, 1, ... manually.
> 
> This is subjectively horrible and, more objectively, would create
> longer mangled names and additional RTTI.

Yeah, it's a neat trick but probably not appropriate to use within the
standard library.

Another reason to avoid it is that GCC's support for lambdas within
template arguments has some known bugs (e.g. PR107457 but that should
hopefully be fixed soon).



[PATCH] libstdc++: Allow adjacent __maybe_present_t to overlap

2024-04-01 Thread Patrick Palka
Tested on x86_64-pc-linux-gnu, does this look OK for trunk?

-- >8 --

Currently __maybe_present_t maps to the same empty class
type independent of T.  This is suboptimal because it means adjacent
__maybe_present_t members with the [[no_unique_address]]
attribute can't overlap even if the conditionally present types are
different.

This patch fixes this by turning this empty class type into a template
parameterized by the conditionally present type, so that

  [[no_unique_address]] __maybe_present_t _M_a;
  [[no_unique_address]] __maybe_present_t _M_b;

now overlap if T and U are different.

This patch goes a step further and also adds an optional integer
discriminator parameter to allow for overlapping when T and U are
the same.

libstdc++-v3/ChangeLog:

* include/std/ranges (ranges::__detail::_Empty): Rename to ...
(ranges::__detail::_Absent): ... this.  Turn into a template
parameterized by the absent type _Tp and discriminator _Disc.
(ranges::__detail::__maybe_present_t): Add an optional
discriminator parameter.
(slide_view::_M_cached_begin): Pass a discriminator argument to
__maybe_present_t.
(slide_view::_M_cached_end): Likewise.
* testsuite/std/ranges/adaptors/sizeof.cc: Verify the size of
slide_view is 3 instead 4 pointers.
---
 libstdc++-v3/include/std/ranges | 13 -
 .../testsuite/std/ranges/adaptors/sizeof.cc |  4 
 2 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 7d739852677..afce818376b 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -886,14 +886,17 @@ namespace views
 
 namespace __detail
 {
-  struct _Empty { };
+  template
+struct _Absent { };
 
   // Alias for a type that is conditionally present
   // (and is an empty type otherwise).
   // Data members using this alias should use [[no_unique_address]] so that
   // they take no space when not needed.
-  template
-using __maybe_present_t = __conditional_t<_Present, _Tp, _Empty>;
+  // The optional template parameter _Disc is for discriminating two otherwise
+  // equivalent absent types so that even they can overlap.
+  template
+using __maybe_present_t = __conditional_t<_Present, _Tp, _Absent<_Tp, 
_Disc>>;
 
   // Alias for a type that is conditionally const.
   template
@@ -6553,10 +6556,10 @@ namespace views::__adaptor
 range_difference_t<_Vp> _M_n;
 [[no_unique_address]]
   __detail::__maybe_present_t<__detail::__slide_caches_first<_Vp>,
- __detail::_CachedPosition<_Vp>> 
_M_cached_begin;
+ __detail::_CachedPosition<_Vp>, 0> 
_M_cached_begin;
 [[no_unique_address]]
   __detail::__maybe_present_t<__detail::__slide_caches_last<_Vp>,
- __detail::_CachedPosition<_Vp>> _M_cached_end;
+ __detail::_CachedPosition<_Vp>, 1> 
_M_cached_end;
 
 template class _Iterator;
 class _Sentinel;
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/sizeof.cc 
b/libstdc++-v3/testsuite/std/ranges/adaptors/sizeof.cc
index 12a9da3181d..08c01704d10 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/sizeof.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/sizeof.cc
@@ -49,3 +49,7 @@ static_assert(sizeof(ranges::lazy_split_view) == 4*ptr);
 
 static_assert
  (sizeof(ranges::reverse_view>) == 
3*ptr);
+
+#if __cpp_lib_ranges_slide
+static_assert(sizeof(ranges::slide_view) == 3*ptr);
+#endif
-- 
2.44.0.448.gc2cbfbd2e2



Re: [PATCH] c++: Keep DECL_SAVED_TREE of destructor instantiations in modules [PR104040]

2024-03-29 Thread Patrick Palka
On Fri, 29 Mar 2024, Nathaniel Shead wrote:

> Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?

LGTM

> 
> -- >8 --
> 
> A template instantiation still needs to have its DECL_SAVED_TREE so that
> its definition is emitted into the CMI. This way it can be emitted in
> the object file of any importers that use it, in case it doesn't end up
> getting emitted in this TU.
> 
>   PR c++/104040
> 
> gcc/cp/ChangeLog:
> 
>   * semantics.cc (expand_or_defer_fn_1): Also keep DECL_SAVED_TREE
>   for template instantiations.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/modules/pr104040_a.C: New test.
>   * g++.dg/modules/pr104040_b.C: New test.
> 
> Signed-off-by: Nathaniel Shead 
> ---
>  gcc/cp/semantics.cc   |  7 +--
>  gcc/testsuite/g++.dg/modules/pr104040_a.C | 14 ++
>  gcc/testsuite/g++.dg/modules/pr104040_b.C |  8 
>  3 files changed, 27 insertions(+), 2 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/modules/pr104040_a.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/pr104040_b.C
> 
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index adb1ba48d29..84e9901509a 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -5033,9 +5033,12 @@ expand_or_defer_fn_1 (tree fn)
>/* We don't want to process FN again, so pretend we've written
>it out, even though we haven't.  */
>TREE_ASM_WRITTEN (fn) = 1;
> -  /* If this is a constexpr function, keep DECL_SAVED_TREE.  */
> +  /* If this is a constexpr function, or the body might need to be
> +  exported from a module CMI, keep DECL_SAVED_TREE.  */
>if (!DECL_DECLARED_CONSTEXPR_P (fn)
> -   && !(modules_p () && DECL_DECLARED_INLINE_P (fn)))
> +   && !(modules_p ()
> +&& (DECL_DECLARED_INLINE_P (fn)
> +|| DECL_TEMPLATE_INSTANTIATION (fn
>   DECL_SAVED_TREE (fn) = NULL_TREE;
>return false;
>  }
> diff --git a/gcc/testsuite/g++.dg/modules/pr104040_a.C 
> b/gcc/testsuite/g++.dg/modules/pr104040_a.C
> new file mode 100644
> index 000..ea36ce0a798
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/modules/pr104040_a.C
> @@ -0,0 +1,14 @@
> +// PR c++/104040
> +// { dg-additional-options "-fmodules-ts" }
> +// { dg-module-cmi test }
> +
> +export module test;
> +
> +export template 
> +struct test {
> +  ~test() {}
> +};
> +
> +test use() {
> +  return {};
> +}
> diff --git a/gcc/testsuite/g++.dg/modules/pr104040_b.C 
> b/gcc/testsuite/g++.dg/modules/pr104040_b.C
> new file mode 100644
> index 000..efe014673fb
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/modules/pr104040_b.C
> @@ -0,0 +1,8 @@
> +// PR c++/104040
> +// { dg-additional-options "-fmodules-ts" }
> +
> +import test;
> +
> +int main() {
> +  test t{};
> +}
> -- 
> 2.43.2
> 
> 



Re: [PATCH] c++: fix alias CTAD [PR114377]

2024-03-27 Thread Patrick Palka
On Mon, 25 Mar 2024, centurion wrote:

> From b34312d82b236601c348382d30e625558f37d40c Mon Sep 17 00:00:00 2001
> From: centurion 
> Date: Mon, 25 Mar 2024 01:57:21 +0400
> Subject: [PATCH] c++: fix alias CTAD [PR114377]
> 
> PR c++/114377
> 
> gcc/cp/ChangeLog:
> 
>   PR c++/114377
>   * pt.cc (find_template_parameter_info::found): Use TREE_TYPE for
>   TEMPLATE_DECL instead of DECL_INITIAL.

Makes sense, this is consistent with e.g. template_parm_to_arg.  LGTM!

> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp2a/class-deduction-alias19.C: New test.
> ---
>  gcc/cp/pt.cc  |  3 ++-
>  .../g++.dg/cpp2a/class-deduction-alias19.C| 15 +++
>  2 files changed, 17 insertions(+), 1 deletion(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-alias19.C
> 
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 8cf0d5b7a8d..d8a02f1cd7f 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -11032,7 +11032,8 @@ find_template_parameter_info::found (tree parm)
>  {
>if (TREE_CODE (parm) == TREE_LIST)
>  parm = TREE_VALUE (parm);
> -  if (TREE_CODE (parm) == TYPE_DECL)
> +  if (TREE_CODE (parm) == TYPE_DECL
> +  || TREE_CODE(parm) == TEMPLATE_DECL)

Style note: there should be a space before the ( of a function/macro call

>  parm = TREE_TYPE (parm);
>else
>  parm = DECL_INITIAL (parm);
> diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias19.C 
> b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias19.C
> new file mode 100644
> index 000..1ea79bd7691
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias19.C
> @@ -0,0 +1,15 @@
> +// PR c++/114377
> +// { dg-do compile { target c++20 } }
> +
> +template  typename Iterator>
> +struct K {};
> +
> +template 
> +class Foo {};
> +
> +template  typename TTP>
> +using Bar = Foo>;
> +
> +void s() {
> +Bar(1); // { dg-error "failed|no match" }
> +}
> -- 
> 2.44.0
> 
> 
> 



Re: [PATCH] c++: templated substitution into lambda-expr [PR114393]

2024-03-27 Thread Patrick Palka
On Mon, 25 Mar 2024, Patrick Palka wrote:

> On Mon, 25 Mar 2024, Patrick Palka wrote:
> 
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
> > for trunk?
> > 
> > -- >8 --
> > 
> > The below testcases use a lambda-expr as a template argument and they
> > all trip over the below added tsubst_lambda_expr sanity check ultimately
> > because current_template_parms is empty, which causes push_template_decl
> > to return error_mark_node from the call to begin_lambda_type.  Were it
> > not for the sanity check this silent error_mark_node result leads to
> > nonsensical errors down the line, or silent breakage.
> > 
> > In the first testcase, we hit this assert during instantiation of the
> > dependent alias template-id c1_t<_Data> from instantiate_template, which
> > clears current_template_parms via push_to_top_level.  Similar story for
> > the second testcase.  For the third testcase we hit the assert during
> > partial instantiation of the member template from instantiate_class_template
> > which similarly calls push_to_top_level.
> > 
> > These testcases illustrate that templated substitution into a lambda-expr
> > is not always possible, in particular when we lost the relevant template
> > context.  I experimented with recovering the template context by making
> > tsubst_lambda_expr fall back to using scope_chain->prev->template_parms if
> > current_template_parms is empty which worked but seemed like a hack.  I
> > also experimented with preserving the template context by keeping
> > current_template_parms set during instantiate_template for a dependent
> > specialization which also worked but it's at odds with the fact that we
> > cache dependent specializations (and so they should be independent of
> > the template context).
> > 
> > So instead of trying to make such substitution work, this patch uses the
> > extra-args mechanism to defer templated substitution into a lambda-expr
> > when we lost the relevant template context.
> > 
> > PR c++/114393
> > PR c++/107457
> > PR c++/93595
> > 
> > gcc/cp/ChangeLog:
> > 
> > * cp-tree.h (LAMBDA_EXPR_EXTRA_ARGS):
> > (struct GTY):
> > * module.cc (trees_out::core_vals) : Stream
> > LAMBDA_EXPR_EXTRA_ARGS.
> > (trees_in::core_vals) : Likewise.
> > * pt.cc (has_extra_args_mechanism_p):
> > (tsubst_lambda_expr):
> 
> Whoops, this version of the patch has an incomplete ChangeLog entry.
> 
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/cpp2a/lambda-targ2.C: New test.
> > * g++.dg/cpp2a/lambda-targ3.C: New test.
> > * g++.dg/cpp2a/lambda-targ4.C: New test.
> > ---
> >  gcc/cp/cp-tree.h  |  5 +
> >  gcc/cp/module.cc  |  2 ++
> >  gcc/cp/pt.cc  | 20 ++--
> >  gcc/testsuite/g++.dg/cpp2a/lambda-targ2.C | 19 +++
> >  gcc/testsuite/g++.dg/cpp2a/lambda-targ3.C | 12 
> >  gcc/testsuite/g++.dg/cpp2a/lambda-targ4.C | 12 
> >  6 files changed, 68 insertions(+), 2 deletions(-)
> >  create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-targ2.C
> >  create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-targ3.C
> >  create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-targ4.C
> > 
> > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> > index c29a5434492..27100537038 100644
> > --- a/gcc/cp/cp-tree.h
> > +++ b/gcc/cp/cp-tree.h
> > @@ -1538,6 +1538,10 @@ enum cp_lambda_default_capture_mode_type {
> >  #define LAMBDA_EXPR_REGEN_INFO(NODE) \
> >(((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->regen_info)
> >  
> > +/* Like PACK_EXPANSION_EXTRA_ARGS, for lambda-expressions.  */
> > +#define LAMBDA_EXPR_EXTRA_ARGS(NODE) \
> > +  (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->extra_args)
> > +
> >  /* The closure type of the lambda, which is also the type of the
> > LAMBDA_EXPR.  */
> >  #define LAMBDA_EXPR_CLOSURE(NODE) \
> > @@ -1550,6 +1554,7 @@ struct GTY (()) tree_lambda_expr
> >tree this_capture;
> >tree extra_scope;
> >tree regen_info;
> > +  tree extra_args;
> >vec *pending_proxies;
> >location_t locus;
> >enum cp_lambda_default_capture_mode_type default_capture_mode : 2;
> > diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> > index 52c60cf370c..1cd890909e3 100644
> > --- a/gcc/cp/module.cc
> > +++ b/gcc/cp/module.cc
>

Re: [PATCH] libstdc++/ranges: Define _S_has_simple_call_op on newer adaptors

2024-03-27 Thread Patrick Palka
On Wed, 17 Jan 2024, Jonathan Wakely wrote:

> 
> 
> On Wed, 17 Jan 2024, 02:37 Patrick Palka,  wrote:
>   Tested on x86_64-pc-linux-gnu, does this look OK for trunk?
> 
> 
> OK

Thanks a lot.  For the record I ended up not pushing this patch because
all the range adaptors it touches are C++23 ones and so ...

> 
> 
> 
>   -- >8 --
> 
>   This compile-time and diagnostic improvement[1] is less important in
>   C++23 mode where deducing this is available and used in _Pipe, but for
>   benefit of C++20 mode

... this isn't true.  There's no real benefit in setting this flag for
standard C++23 range adaptors (besides consistency I guess, but OTOH not
setting it means more testing coverage for the deducing this code path).

> and for consistency let's set the flag on the most
>   recently added range adaptors which lack it.
> 
>   [1]: Defining _S_has_simple_call_op=true for a range adaptor closure
>   object signals that the adaptor has an operator() that's not overloaded
>   according to the constness/value category of the object, which in turn
>   allows us to implement the operator() of the composition of such 
> adaptors
>   in a simpler way.
> 
>   libstdc++-v3/ChangeLog:
> 
>           * include/std/ranges (views::_Adjacent::_S_has_simple_call_op):
>           Define to true.
>           (views::_AsRvalue::_S_has_simple_call_op): Likewise.
>           (views::_Enumerate::_S_has_simple_call_op): Likewise.
>           (views::_AsConst::_S_has_simple_call_op): Likewise.
>   ---
>    libstdc++-v3/include/std/ranges | 8 
>    1 file changed, 8 insertions(+)
> 
>   diff --git a/libstdc++-v3/include/std/ranges 
> b/libstdc++-v3/include/std/ranges
>   index 7ef835f486a..66502cc1da4 100644
>   --- a/libstdc++-v3/include/std/ranges
>   +++ b/libstdc++-v3/include/std/ranges
>   @@ -5669,6 +5669,8 @@ namespace views::__adaptor
>               else
>                 return adjacent_view, 
> _Nm>(std::forward<_Range>(__r));
>             }
>   +
>   +       static constexpr bool _S_has_simple_call_op = true;
>          };
> 
>        template
>   @@ -8844,6 +8846,8 @@ namespace views::__adaptor
>             else
>               return as_rvalue_view(std::forward<_Range>(__r));
>           }
>   +
>   +      static constexpr bool _S_has_simple_call_op = true;
>        };
> 
>        inline constexpr _AsRvalue as_rvalue;
>   @@ -9147,6 +9151,8 @@ namespace views::__adaptor
>           constexpr auto
>           operator() [[nodiscard]] (_Range&& __r) const
>           { return 
> enumerate_view>(std::forward<_Range>(__r)); }
>   +
>   +      static constexpr bool _S_has_simple_call_op = true;
>        };
> 
>        inline constexpr _Enumerate enumerate;
>   @@ -9253,6 +9259,8 @@ namespace views::__adaptor
>           else
>             return as_const_view(std::forward<_Range>(__r));
>          }
>   +
>   +      static constexpr bool _S_has_simple_call_op = true;
>        };
> 
>        inline constexpr _AsConst as_const;
>   --
>   2.43.0.367.g186b115d30
> 
> 
> 

Re: [PATCH] c++/modules: optimize tree flag streaming

2024-03-26 Thread Patrick Palka
On Tue, 27 Feb 2024, Patrick Palka wrote:

> On Fri, 16 Feb 2024, Patrick Palka wrote:
> 
> > On Thu, 15 Feb 2024, Patrick Palka wrote:
> > 
> > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> > > OK for trunk?
> > > 
> > > -- >8 --
> > > 
> > > One would expect consecutive calls to bytes_in/out::b for streaming
> > > adjacent bits, as we do for tree flag streaming, to at least be
> > > optimized by the compiler into individual bit operations using
> > > statically known bit positions (and ideally merged into larger sized
> > > reads/writes).
> > > 
> > > Unfortunately this doesn't happen because the compiler has trouble
> > > tracking the values of this->bit_pos and this->bit_val across such
> > > calls, likely because the compiler doesn't know 'this' and so it's
> > > treated as global memory.  This means for each consecutive bit stream
> > > operation, bit_pos and bit_val are loaded from memory, checked if
> > > buffering is needed, and finally the bit is extracted from bit_val
> > > according to the (unknown) bit_pos, even though relative to the previous
> > > operation (if we didn't need to buffer) bit_val is unchanged and bit_pos
> > > is just 1 larger.  This ends up being quite slow, with tree_node_bools
> > > taking 10% of time when streaming in parts of the std module.
> > > 
> > > This patch optimizes this by making tracking of bit_pos and bit_val
> > > easier for the compiler.  Rather than bit_pos and bit_val being members
> > > of the (effectively global) bytes_in/out objects, this patch factors out
> > > the bit streaming code/state into separate classes bits_in/out that get
> > > constructed locally as needed for bit streaming.  Since these objects
> > > are now clearly local, the compiler can more easily track their values.
> > > 
> > > And since bit streaming is intended to be batched it's natural for these
> > > new classes to be RAII-enabled such that the bit stream is flushed upon
> > > destruction.
> > > 
> > > In order to make the most of this improved tracking of bit position,
> > > this patch changes parts where we conditionally stream a tree flag
> > > to unconditionally stream (the flag or a dummy value).  That way
> > > the number of bits streamed and the respective bit positions are as
> > > statically known as reasonably possible.  In lang_decl_bools and
> > > lang_type_bools we flush the current bit buffer at the start so that
> > > subsequent bit positions are statically known.  And in core bools, we
> > > can add explicit early exits utilizing invariants that the compiler
> > > can't figure out itself (e.g. a tree code can't have both TS_TYPE_COMMON
> > > and TS_DECL_COMMON, and if a tree code doesn't have TS_DECL_COMMON then
> > > it doesn't have TS_DECL_WITH_VIS).  Finally if we're streaming fewer
> > > than 4 bits, it's more space efficient to stream them as individual
> > > bytes rather than as packed bits (due to the 32-bit buffer).
> > 
> > Oops, this last sentence is wrong.  Although the size of the bit buffer
> > is 32 bits, upon flushing we rewind unused bytes within the buffer,
> > which means streaming 2-8 bits ends up using only one byte not all four.
> > So v2 below undoes this pessimization.
> > 
> > > This patch also moves the definitions of the relevant streaming classes
> > > into anonymous namespaces so that the compiler can make more informed
> > > decisions about inlining their member functions.
> > > 
> > > After this patch, compile time for a simple Hello World using the std
> > > module is reduced by 7% with a release compiler.  The on-disk size of
> > > the std module increases by 0.7% (presumably due to the extra flushing
> > > done in lang_decl_bools and lang_type_bools).
> > 
> > The on-disk std module now only grows 0.4% instead of 0.7%.
> > 
> > > 
> > > The bit stream out performance isn't improved as much as the stream in
> > > due to the spans/lengths instrumentation performed on stream out (which
> > > probably should be e.g. removed for release builds?)
> > 
> > -- >8 --
> > 
> > gcc/cp/ChangeLog:
> > 
> > * module.cc: Update comment about classes defined.
> > (class data): Enclose in an anonymous namespace.
> > (data::calc_crc): Moved from bytes::calc_crc.
> > (class bytes): Remove.  Move bit_flush to namespace scope.
> > (class bytes_in): Enclos

Re: [PATCH] c++/modules: local class merging [PR99426]

2024-03-26 Thread Patrick Palka
On Tue, 5 Mar 2024, Patrick Palka wrote:

> On Tue, 27 Feb 2024, Patrick Palka wrote:
> 
> > On Mon, 26 Feb 2024, Patrick Palka wrote:
> > 
> > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this approach
> > > look reasonable?
> > > 
> > > -- >8 --
> > > 
> > > One known missing piece in the modules implementation is merging of a
> > > streamed-in local class with the corresponding in-TU version of the
> > > local class.  This missing piece turns out to cause a hard-to-reduce
> > > use-after-free GC issue due to the entity_ary not being marked as a GC
> > > root (deliberately), and manifests as a serialization error on stream-in
> > > as in PR99426 (see comment #6 for a reduction).  It's also reproducible
> > > on trunk when running the xtreme-header tests without -fno-module-lazy.
> > > 
> > > This patch makes us merge such local classes according to their position
> > > within the containing function's definition, similar to how we merge
> > > FIELD_DECLs of a class according to their index in the TYPE_FIELDS
> > > list.
> > > 
> > >   PR c++/99426
> > > 
> > > gcc/cp/ChangeLog:
> > > 
> > >   * module.cc (merge_kind::MK_local_class): New enumerator.
> > >   (merge_kind_name): Update.
> > >   (trees_out::chained_decls): Move BLOCK-specific handling
> > >   of DECL_LOCAL_DECL_P decls to ...
> > >   (trees_out::core_vals) : ... here.  Stream
> > >   BLOCK_VARS manually.
> > >   (trees_in::core_vals) : Stream BLOCK_VARS
> > >   manually.  Handle deduplicated local classes.
> > >   (trees_out::key_local_class): Define.
> > >   (trees_in::key_local_class): Define.
> > >   (trees_out::get_merge_kind) : Return
> > >   MK_local_class for a local class.
> > >   (trees_out::key_mergeable) : Use
> > >   key_local_class.
> > >   (trees_in::key_mergeable) : Likewise.
> > >   (trees_in::is_matching_decl): Be flexible with type mismatches
> > >   for local entities.
> > > 
> > > gcc/testsuite/ChangeLog:
> > > 
> > >   * g++.dg/modules/xtreme-header-7_a.H: New test.
> > >   * g++.dg/modules/xtreme-header-7_b.C: New test.
> > 
> > > ---
> > >  gcc/cp/module.cc  | 167 +++---
> > >  .../g++.dg/modules/xtreme-header-7_a.H|   4 +
> > >  .../g++.dg/modules/xtreme-header-7_b.C|   6 +
> > >  3 files changed, 149 insertions(+), 28 deletions(-)
> > >  create mode 100644 gcc/testsuite/g++.dg/modules/xtreme-header-7_a.H
> > >  create mode 100644 gcc/testsuite/g++.dg/modules/xtreme-header-7_b.C
> > > 
> > > diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> > > index fa91c6ff9cb..f77f73a59ed 100644
> > > --- a/gcc/cp/module.cc
> > > +++ b/gcc/cp/module.cc
> > > @@ -2771,6 +2771,7 @@ enum merge_kind
> > >  
> > >MK_enum,   /* Found by CTX, & 1stMemberNAME.  */
> > >MK_keyed, /* Found by key & index.  */
> > > +  MK_local_class, /* Found by CTX, index.  */
> > >  
> > >MK_friend_spec,  /* Like named, but has a tmpl & args too.  */
> > >MK_local_friend, /* Found by CTX, index.  */
> > > @@ -2799,7 +2800,7 @@ static char const *const merge_kind_name[MK_hwm] =
> > >  "unique", "named", "field", "vtable",/* 0...3  */
> > >  "asbase", "partial", "enum", "attached", /* 4...7  */
> > >  
> > > -"friend spec", "local friend", NULL, NULL,  /* 8...11 */
> > > +"local class", "friend spec", "local friend", NULL,  /* 8...11 */
> > >  NULL, NULL, NULL, NULL,
> > >  
> > >  "type spec", "type tmpl spec",   /* 16,17 type (template).  */
> > > @@ -2928,6 +2929,7 @@ public:
> > >unsigned binfo_mergeable (tree *);
> > >  
> > >  private:
> > > +  tree key_local_class (const merge_key&, tree);
> > >uintptr_t *find_duplicate (tree existing);
> > >void register_duplicate (tree decl, tree existing);
> > >/* Mark as an already diagnosed bad duplicate.  */
> > > @@ -3086,6 +3088,7 @@ public:
> > >void binfo_mergeable (tree binfo);
> > >  
> > >  private:
> > > +  void key_local_class (merge_key&, tree, tree);
> > >bool decl_node (tree, walk

Re: [PATCH] c++: recalculating local specs via build_extra_args [PR114303]

2024-03-26 Thread Patrick Palka
On Mon, 11 Mar 2024, Patrick Palka wrote:

> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> OK for trunk and release branches?

Ping.

> 
> -- >8 --
> 
> r13-6452-g341e6cd8d603a3 made build_extra_args walk evaluated contexts
> first so that we prefer processing a local specialization in an evaluated
> context even if its first use is in an unevaluated context.  But this
> means we need to avoid walking a tree that already has extra args/specs
> saved because the list of saved specs appears to be an evaluated
> context.  It seems then that we should be calculating the saved specs
> from scratch each time, rather than potentially walking the saved specs
> list from an earlier partial instantiation when calling build_extra_args
> a second time around.
> 
>   PR c++/114303
> 
> gcc/cp/ChangeLog:
> 
>   * constraint.cc (tsubst_requires_expr): Clear
>   REQUIRES_EXPR_EXTRA_ARGS before calling build_extra_args.
>   * pt.cc (tsubst_stmt) : Call build_extra_args
>   on the new IF_STMT instead of t which might already have
>   IF_STMT_EXTRA_ARGS.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp1z/constexpr-if-lambda6.C: New test.
> ---
>  gcc/cp/constraint.cc |  1 +
>  gcc/cp/pt.cc |  2 +-
>  .../g++.dg/cpp1z/constexpr-if-lambda6.C  | 16 
>  3 files changed, 18 insertions(+), 1 deletion(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C
> 
> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> index 49de3211d4c..8a3b5d80ba7 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -2362,6 +2362,7 @@ tsubst_requires_expr (tree t, tree args, sat_info info)
>matching or dguide constraint rewriting), in which case we need
>to partially substitute.  */
>t = copy_node (t);
> +  REQUIRES_EXPR_EXTRA_ARGS (t) = NULL_TREE;
>REQUIRES_EXPR_EXTRA_ARGS (t) = build_extra_args (t, args, 
> info.complain);
>return t;
>  }
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 8cf0d5b7a8d..37f2392d035 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -18718,7 +18718,7 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t 
> complain, tree in_decl)
> IF_COND (stmt) = IF_COND (t);
> THEN_CLAUSE (stmt) = THEN_CLAUSE (t);
> ELSE_CLAUSE (stmt) = ELSE_CLAUSE (t);
> -   IF_STMT_EXTRA_ARGS (stmt) = build_extra_args (t, args, complain);
> +   IF_STMT_EXTRA_ARGS (stmt) = build_extra_args (stmt, args, complain);
> add_stmt (stmt);
> break;
>   }
> diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C 
> b/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C
> new file mode 100644
> index 000..038c2a41210
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C
> @@ -0,0 +1,16 @@
> +// PR c++/114303
> +// { dg-do compile { target c++17 } }
> +
> +struct A { static constexpr bool value = true; };
> +
> +int main() {
> +  [](auto x1) {
> +return [&](auto) {
> +  return [&](auto x3) {
> +if constexpr (decltype(x3)::value) {
> +  static_assert(decltype(x1)::value);
> +}
> +  }(A{});
> +}(0);
> +  }(A{});
> +}
> -- 
> 2.44.0.165.ge09f1254c5
> 
> 



[pushed] c++/modules testsuite: fix a couple of dg-module-do directives

2024-03-26 Thread Patrick Palka
Tested on x86_64-pc-linux-gnu, committed to trunk as obvious.

-- >8 --

gcc/testsuite/ChangeLog:

* g++.dg/modules/decltype-1_a.C: Add missing } to dg-module-do
directive.
* g++.dg/modules/lambda-5_a.C: Likewise.
---
 gcc/testsuite/g++.dg/modules/decltype-1_a.C | 2 +-
 gcc/testsuite/g++.dg/modules/lambda-5_a.C   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/gcc/testsuite/g++.dg/modules/decltype-1_a.C 
b/gcc/testsuite/g++.dg/modules/decltype-1_a.C
index ca66e8b598a..e4202a26de4 100644
--- a/gcc/testsuite/g++.dg/modules/decltype-1_a.C
+++ b/gcc/testsuite/g++.dg/modules/decltype-1_a.C
@@ -1,5 +1,5 @@
 // PR c++/105322
-// { dg-module-do link
+// { dg-module-do link }
 // { dg-additional-options -fmodules-ts }
 // { dg-module-cmi pr105322.Decltype }
 
diff --git a/gcc/testsuite/g++.dg/modules/lambda-5_a.C 
b/gcc/testsuite/g++.dg/modules/lambda-5_a.C
index 6b589d4965c..37d0e77b1e1 100644
--- a/gcc/testsuite/g++.dg/modules/lambda-5_a.C
+++ b/gcc/testsuite/g++.dg/modules/lambda-5_a.C
@@ -1,5 +1,5 @@
 // PR c++/105322
-// { dg-module-do link
+// { dg-module-do link }
 // { dg-additional-options -fmodules-ts }
 // { dg-module-cmi pr105322.Lambda }
 
-- 
2.44.0.368.gc75fd8d815



Re: [PATCH] c++: problematic assert in reference_binding [PR113141]

2024-03-26 Thread Patrick Palka
On Thu, 7 Mar 2024, Jason Merrill wrote:

> On 1/29/24 17:42, Patrick Palka wrote:
> > On Mon, 29 Jan 2024, Patrick Palka wrote:
> > 
> > > On Fri, 26 Jan 2024, Jason Merrill wrote:
> > > 
> > > > On 1/26/24 17:11, Jason Merrill wrote:
> > > > > On 1/26/24 16:52, Jason Merrill wrote:
> > > > > > On 1/25/24 14:18, Patrick Palka wrote:
> > > > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> > > > > > > OK for trunk/13?  This isn't a very satisfactory fix, but at least
> > > > > > > it safely fixes these testcases I guess.  Note that there's
> > > > > > > implementation disagreement about the second testcase, GCC always
> > > > > > > accepted it but Clang/MSVC/icc reject it.
> > > > > > 
> > > > > > Because of trying to initialize int& from {c}; removing the extra
> > > > > > braces
> > > > > > makes it work everywhore.
> > > > > > 
> > > > > > https://eel.is/c++draft/dcl.init#list-3.10 says that we always
> > > > > > generate a
> > > > > > prvalue in this case, so perhaps we shouldn't recalculate if the
> > > > > > initializer is an init-list?
> > > > > 
> > > > > ...but it seems bad to silently bind a const int& to a prvalue instead
> > > > > of
> > > > > directly to the reference returned by the operator, as clang does if
> > > > > we add
> > > > > const to the second testcase, so I think there's a defect in the
> > > > > standard
> > > > > here.
> > > > 
> > > > Perhaps bullet 3.9 should change to "...its referenced type is
> > > > reference-related to E or scalar, ..."
> > > > 
> > > > > Maybe for now also disable the maybe_valid heuristics in the case of
> > > > > an
> > > > > init-list?
> > > > > 
> > > > > > The first testcase is special because it's a C-style cast; seems
> > > > > > like the
> > > > > > maybe_valid = false heuristics should be disabled if c_cast_p.
> > > 
> > > Thanks a lot for the pointers.  IIUC c_cast_p and
> > > LOOKUP_SHORTCUT_BAD_CONVS
> > > should already be mutually exclusive, since the latter is set only when
> > > computing argument conversions, so it shouldn't be necessary to check
> > > c_cast_p.
> > > 
> > > I suppose we could disable the heuristic for init-lists, but after some
> > > digging I noticed that the heuristics were originally in same spot they
> > > are now until r5-601-gd02f620dc0bb3b moved them to get checked after
> > > the recursive recalculation case in reference_binding, returning a bad
> > > conversion instead of NULL.  (Then in r13-1755-g68f37670eff0b872 I moved
> > > them back; IIRC that's why I felt confident that moving the checks was
> > > safe.)
> > > Thus we didn't always accept the second testcase, we only started doing so
> > > in
> > > GCC 5: https://godbolt.org/z/6nsEW14fh (sorry for missing this and saying
> > > we
> > > always accepted it)
> > > 
> > > And indeed the current order of checks seems consistent with that of
> > > [dcl.init.ref]/5.  So I wonder if we don't instead want to "complete"
> > > the NULL-to-bad-conversion adjustment in r5-601-gd02f620dc0bb3b and
> > > do:
> > > 
> > > gcc/cp/ChangeLog:
> > > 
> > >   * call.cc (reference_binding): Set bad_p according to
> > >   maybe_valid_p in the recursive case as well.  Remove
> > >   redundant gcc_assert.
> > > 
> > > diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
> > > index 9de0d77c423..c4158b2af37 100644
> > > --- a/gcc/cp/call.cc
> > > +++ b/gcc/cp/call.cc
> > > @@ -2033,8 +2033,8 @@ reference_binding (tree rto, tree rfrom, tree expr,
> > > bool c_cast_p, int flags,
> > >  sflags, complain);
> > >   if (!new_second)
> > > return bad_direct_conv ? bad_direct_conv : nullptr;
> > > + t->bad_p = !maybe_valid_p;
> > 
> > Oops, that should be |= not =.
> > 
> > > > Perhaps bullet 3.9 should change to "...its referenced type is
> > > > reference-related to E or scalar, ..."
> > >   conv = merge_conversion_se

Re: [PATCH] c++: templated substitution into lambda-expr [PR114393]

2024-03-25 Thread Patrick Palka
On Mon, 25 Mar 2024, Patrick Palka wrote:

> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
> for trunk?
> 
> -- >8 --
> 
> The below testcases use a lambda-expr as a template argument and they
> all trip over the below added tsubst_lambda_expr sanity check ultimately
> because current_template_parms is empty, which causes push_template_decl
> to return error_mark_node from the call to begin_lambda_type.  Were it
> not for the sanity check this silent error_mark_node result leads to
> nonsensical errors down the line, or silent breakage.
> 
> In the first testcase, we hit this assert during instantiation of the
> dependent alias template-id c1_t<_Data> from instantiate_template, which
> clears current_template_parms via push_to_top_level.  Similar story for
> the second testcase.  For the third testcase we hit the assert during
> partial instantiation of the member template from instantiate_class_template
> which similarly calls push_to_top_level.
> 
> These testcases illustrate that templated substitution into a lambda-expr
> is not always possible, in particular when we lost the relevant template
> context.  I experimented with recovering the template context by making
> tsubst_lambda_expr fall back to using scope_chain->prev->template_parms if
> current_template_parms is empty which worked but seemed like a hack.  I
> also experimented with preserving the template context by keeping
> current_template_parms set during instantiate_template for a dependent
> specialization which also worked but it's at odds with the fact that we
> cache dependent specializations (and so they should be independent of
> the template context).
> 
> So instead of trying to make such substitution work, this patch uses the
> extra-args mechanism to defer templated substitution into a lambda-expr
> when we lost the relevant template context.
> 
>   PR c++/114393
>   PR c++/107457
>   PR c++/93595
> 
> gcc/cp/ChangeLog:
> 
>   * cp-tree.h (LAMBDA_EXPR_EXTRA_ARGS):
>   (struct GTY):
>   * module.cc (trees_out::core_vals) : Stream
>   LAMBDA_EXPR_EXTRA_ARGS.
>   (trees_in::core_vals) : Likewise.
>   * pt.cc (has_extra_args_mechanism_p):
>   (tsubst_lambda_expr):

Whoops, this version of the patch has an incomplete ChangeLog entry.

> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp2a/lambda-targ2.C: New test.
>   * g++.dg/cpp2a/lambda-targ3.C: New test.
>   * g++.dg/cpp2a/lambda-targ4.C: New test.
> ---
>  gcc/cp/cp-tree.h  |  5 +
>  gcc/cp/module.cc  |  2 ++
>  gcc/cp/pt.cc  | 20 ++--
>  gcc/testsuite/g++.dg/cpp2a/lambda-targ2.C | 19 +++
>  gcc/testsuite/g++.dg/cpp2a/lambda-targ3.C | 12 
>  gcc/testsuite/g++.dg/cpp2a/lambda-targ4.C | 12 
>  6 files changed, 68 insertions(+), 2 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-targ2.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-targ3.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-targ4.C
> 
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index c29a5434492..27100537038 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -1538,6 +1538,10 @@ enum cp_lambda_default_capture_mode_type {
>  #define LAMBDA_EXPR_REGEN_INFO(NODE) \
>(((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->regen_info)
>  
> +/* Like PACK_EXPANSION_EXTRA_ARGS, for lambda-expressions.  */
> +#define LAMBDA_EXPR_EXTRA_ARGS(NODE) \
> +  (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->extra_args)
> +
>  /* The closure type of the lambda, which is also the type of the
> LAMBDA_EXPR.  */
>  #define LAMBDA_EXPR_CLOSURE(NODE) \
> @@ -1550,6 +1554,7 @@ struct GTY (()) tree_lambda_expr
>tree this_capture;
>tree extra_scope;
>tree regen_info;
> +  tree extra_args;
>vec *pending_proxies;
>location_t locus;
>enum cp_lambda_default_capture_mode_type default_capture_mode : 2;
> diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> index 52c60cf370c..1cd890909e3 100644
> --- a/gcc/cp/module.cc
> +++ b/gcc/cp/module.cc
> @@ -6312,6 +6312,7 @@ trees_out::core_vals (tree t)
>WT (((lang_tree_node *)t)->lambda_expression.this_capture);
>WT (((lang_tree_node *)t)->lambda_expression.extra_scope);
>WT (((lang_tree_node *)t)->lambda_expression.regen_info);
> +  WT (((lang_tree_node *)t)->lambda_expression.extra_args);
>/* pending_proxies is a parse-time thing.  */
>gcc_assert (!((lang_tree_node *)t)->lambda_expression.pending_proxies);
>

[PATCH] c++: templated substitution into lambda-expr [PR114393]

2024-03-25 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
for trunk?

-- >8 --

The below testcases use a lambda-expr as a template argument and they
all trip over the below added tsubst_lambda_expr sanity check ultimately
because current_template_parms is empty, which causes push_template_decl
to return error_mark_node from the call to begin_lambda_type.  Were it
not for the sanity check this silent error_mark_node result leads to
nonsensical errors down the line, or silent breakage.

In the first testcase, we hit this assert during instantiation of the
dependent alias template-id c1_t<_Data> from instantiate_template, which
clears current_template_parms via push_to_top_level.  Similar story for
the second testcase.  For the third testcase we hit the assert during
partial instantiation of the member template from instantiate_class_template
which similarly calls push_to_top_level.

These testcases illustrate that templated substitution into a lambda-expr
is not always possible, in particular when we lost the relevant template
context.  I experimented with recovering the template context by making
tsubst_lambda_expr fall back to using scope_chain->prev->template_parms if
current_template_parms is empty which worked but seemed like a hack.  I
also experimented with preserving the template context by keeping
current_template_parms set during instantiate_template for a dependent
specialization which also worked but it's at odds with the fact that we
cache dependent specializations (and so they should be independent of
the template context).

So instead of trying to make such substitution work, this patch uses the
extra-args mechanism to defer templated substitution into a lambda-expr
when we lost the relevant template context.

PR c++/114393
PR c++/107457
PR c++/93595

gcc/cp/ChangeLog:

* cp-tree.h (LAMBDA_EXPR_EXTRA_ARGS):
(struct GTY):
* module.cc (trees_out::core_vals) : Stream
LAMBDA_EXPR_EXTRA_ARGS.
(trees_in::core_vals) : Likewise.
* pt.cc (has_extra_args_mechanism_p):
(tsubst_lambda_expr):

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/lambda-targ2.C: New test.
* g++.dg/cpp2a/lambda-targ3.C: New test.
* g++.dg/cpp2a/lambda-targ4.C: New test.
---
 gcc/cp/cp-tree.h  |  5 +
 gcc/cp/module.cc  |  2 ++
 gcc/cp/pt.cc  | 20 ++--
 gcc/testsuite/g++.dg/cpp2a/lambda-targ2.C | 19 +++
 gcc/testsuite/g++.dg/cpp2a/lambda-targ3.C | 12 
 gcc/testsuite/g++.dg/cpp2a/lambda-targ4.C | 12 
 6 files changed, 68 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-targ2.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-targ3.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-targ4.C

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index c29a5434492..27100537038 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1538,6 +1538,10 @@ enum cp_lambda_default_capture_mode_type {
 #define LAMBDA_EXPR_REGEN_INFO(NODE) \
   (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->regen_info)
 
+/* Like PACK_EXPANSION_EXTRA_ARGS, for lambda-expressions.  */
+#define LAMBDA_EXPR_EXTRA_ARGS(NODE) \
+  (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->extra_args)
+
 /* The closure type of the lambda, which is also the type of the
LAMBDA_EXPR.  */
 #define LAMBDA_EXPR_CLOSURE(NODE) \
@@ -1550,6 +1554,7 @@ struct GTY (()) tree_lambda_expr
   tree this_capture;
   tree extra_scope;
   tree regen_info;
+  tree extra_args;
   vec *pending_proxies;
   location_t locus;
   enum cp_lambda_default_capture_mode_type default_capture_mode : 2;
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 52c60cf370c..1cd890909e3 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -6312,6 +6312,7 @@ trees_out::core_vals (tree t)
   WT (((lang_tree_node *)t)->lambda_expression.this_capture);
   WT (((lang_tree_node *)t)->lambda_expression.extra_scope);
   WT (((lang_tree_node *)t)->lambda_expression.regen_info);
+  WT (((lang_tree_node *)t)->lambda_expression.extra_args);
   /* pending_proxies is a parse-time thing.  */
   gcc_assert (!((lang_tree_node *)t)->lambda_expression.pending_proxies);
   if (state)
@@ -6814,6 +6815,7 @@ trees_in::core_vals (tree t)
   RT (((lang_tree_node *)t)->lambda_expression.this_capture);
   RT (((lang_tree_node *)t)->lambda_expression.extra_scope);
   RT (((lang_tree_node *)t)->lambda_expression.regen_info);
+  RT (((lang_tree_node *)t)->lambda_expression.extra_args);
   /* lambda_expression.pending_proxies is NULL  */
   ((lang_tree_node *)t)->lambda_expression.locus
= state->read_location (*this);
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 8cf0d5b7a8d..b1a9ee2b385 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -3855,7 +3855,8 @@ has_extra_args_mechanism_p 

Re: [PATCH] c++: ICE with noexcept and local specialization [PR114114]

2024-03-15 Thread Patrick Palka
On Fri, 15 Mar 2024, Marek Polacek wrote:

> On Fri, Mar 15, 2024 at 10:35:07AM -0400, Patrick Palka wrote:
> > On Tue, 5 Mar 2024, Marek Polacek wrote:
> > 
> > > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> > > 
> > > -- >8 --
> > > Here we ICE because we call register_local_specialization while
> > > local_specializations is null, so
> > > 
> > >   local_specializations->put ();
> > > 
> > > crashes on null this.  It's null since maybe_instantiate_noexcept calls
> > > push_to_top_level which creates a new scope.  Normally, I would have
> > > guessed that we need a new local_specialization_stack.  But here we're
> > > dealing with an operand of a noexcept, which is an unevaluated operand,
> > > and those aren't registered in the hash map.  maybe_instantiate_noexcept
> > > wasn't signalling that it's substituting an unevaluated operand though.
> > 
> > It thought it was noexcept-exprs rather than noexcept-specs that are
> > unevaluated contexts?
> 
> Yes, sigh.  It would have to be noexcept(noexcept(x)).  I was looking at
> cp_parser_unary_expression/RID_NOEXCEPT but that's a noexcept-expr.  So
> what can we do here, set a new local_specialization_stack?  That wasn't
> that straightforward when I tried.  Or maybe just

Maybe we can avoid doing push_to_top_level (which clears
local_specializations) from maybe_instantiate_noexcept if
current_function_decl == fn?

Relatedly I wonder if we can avoid calling regenerate_decl_from_template
for local class member functions since they can't be redeclared?

> 
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -15649,7 +15649,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t 
> complain,
>   {
> if (DECL_LANG_SPECIFIC (r))
>   DECL_TEMPLATE_INFO (r) = NULL_TREE;
> -   if (!cp_unevaluated_operand)
> +   if (!cp_unevaluated_operand && local_specializations)
>   register_local_specialization (r, t);
>   }
> 
> ?
> 
> 



Re: [PATCH] c++: ICE with noexcept and local specialization [PR114114]

2024-03-15 Thread Patrick Palka
On Tue, 5 Mar 2024, Marek Polacek wrote:

> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> 
> -- >8 --
> Here we ICE because we call register_local_specialization while
> local_specializations is null, so
> 
>   local_specializations->put ();
> 
> crashes on null this.  It's null since maybe_instantiate_noexcept calls
> push_to_top_level which creates a new scope.  Normally, I would have
> guessed that we need a new local_specialization_stack.  But here we're
> dealing with an operand of a noexcept, which is an unevaluated operand,
> and those aren't registered in the hash map.  maybe_instantiate_noexcept
> wasn't signalling that it's substituting an unevaluated operand though.

It thought it was noexcept-exprs rather than noexcept-specs that are
unevaluated contexts?

> 
>   PR c++/114114
> 
> gcc/cp/ChangeLog:
> 
>   * pt.cc (maybe_instantiate_noexcept): Save/restore
>   cp_unevaluated_operand, c_inhibit_evaluation_warnings, and
>   cp_noexcept_operand around the tsubst_expr call.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp0x/noexcept84.C: New test.
> ---
>  gcc/cp/pt.cc|  6 +
>  gcc/testsuite/g++.dg/cpp0x/noexcept84.C | 32 +
>  2 files changed, 38 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/cpp0x/noexcept84.C
> 
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index c4bc54a8fdb..11f7d33c766 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -26869,10 +26869,16 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t 
> complain)
> if (orig_fn)
>   ++processing_template_decl;
>  
> +   ++cp_unevaluated_operand;
> +   ++c_inhibit_evaluation_warnings;
> +   ++cp_noexcept_operand;
> /* Do deferred instantiation of the noexcept-specifier.  */
> noex = tsubst_expr (DEFERRED_NOEXCEPT_PATTERN (noex),
> DEFERRED_NOEXCEPT_ARGS (noex),
> tf_warning_or_error, fn);
> +   --cp_unevaluated_operand;
> +   --c_inhibit_evaluation_warnings;
> +   --cp_noexcept_operand;
>  
> /* Build up the noexcept-specification.  */
> spec = build_noexcept_spec (noex, tf_warning_or_error);
> diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept84.C 
> b/gcc/testsuite/g++.dg/cpp0x/noexcept84.C
> new file mode 100644
> index 000..06f33264f77
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/noexcept84.C
> @@ -0,0 +1,32 @@
> +// PR c++/114114
> +// { dg-do compile { target c++11 } }
> +
> +template
> +constexpr void
> +test ()
> +{
> +  constexpr bool is_yes = B;
> +  struct S {
> +constexpr S() noexcept(is_yes) { }
> +  };
> +  S s;
> +}
> +
> +constexpr bool foo() { return true; }
> +
> +template
> +constexpr void
> +test2 ()
> +{
> +  constexpr T (*pfn)() = 
> +  struct S {
> +constexpr S() noexcept(pfn()) { }
> +  };
> +  S s;
> +}
> +
> +int main()
> +{
> +  test();
> +  test2();
> +}
> 
> base-commit: 8776468d9e57ace5f832c1368243a6dbce9984d5
> -- 
> 2.44.0
> 
> 



Re: [PATCH] c++: recalculating local specs via build_extra_args [PR114303]

2024-03-12 Thread Patrick Palka
On Tue, 12 Mar 2024, Patrick Palka wrote:

> On Tue, 12 Mar 2024, Jason Merrill wrote:
> 
> > On 3/11/24 12:53, Patrick Palka wrote:
> > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> > > OK for trunk and release branches?
> > > 
> > > -- >8 --
> > > 
> > > r13-6452-g341e6cd8d603a3 made build_extra_args walk evaluated contexts
> > > first so that we prefer processing a local specialization in an evaluated
> > > context even if its first use is in an unevaluated context.  But this
> > > means we need to avoid walking a tree that already has extra args/specs
> > > saved because the list of saved specs appears to be an evaluated
> > > context.  It seems then that we should be calculating the saved specs
> > > from scratch each time, rather than potentially walking the saved specs
> > > list from an earlier partial instantiation when calling build_extra_args
> > > a second time around.
> > 
> > Makes sense, but I wonder if we want to approach that by avoiding walking 
> > into
> > *_EXTRA_ARGS in extract_locals_r?  Or do we still want to walk into any 
> > nested
> > extra args?  And if so, will we run into this same problem then?
> 
> I'm not sure totally but I'd expect a nested extra-args tree to always
> have empty *_EXTRA_ARGS since the outer extra-args tree should intercept
> any substitution before the inner extra-args tree can see it?

... and so in extract_locals_r I think we can assume *_EXTRA_ARGS is
empty, and not have to explicitly avoid walking it.

> 
> > 
> > >   PR c++/114303
> > > 
> > > gcc/cp/ChangeLog:
> > > 
> > >   * constraint.cc (tsubst_requires_expr): Clear
> > >   REQUIRES_EXPR_EXTRA_ARGS before calling build_extra_args.
> > >   * pt.cc (tsubst_stmt) : Call build_extra_args
> > >   on the new IF_STMT instead of t which might already have
> > >   IF_STMT_EXTRA_ARGS.
> > > 
> > > gcc/testsuite/ChangeLog:
> > > 
> > >   * g++.dg/cpp1z/constexpr-if-lambda6.C: New test.
> > > ---
> > >   gcc/cp/constraint.cc |  1 +
> > >   gcc/cp/pt.cc |  2 +-
> > >   .../g++.dg/cpp1z/constexpr-if-lambda6.C  | 16 
> > >   3 files changed, 18 insertions(+), 1 deletion(-)
> > >   create mode 100644 gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C
> > > 
> > > diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> > > index 49de3211d4c..8a3b5d80ba7 100644
> > > --- a/gcc/cp/constraint.cc
> > > +++ b/gcc/cp/constraint.cc
> > > @@ -2362,6 +2362,7 @@ tsubst_requires_expr (tree t, tree args, sat_info
> > > info)
> > >matching or dguide constraint rewriting), in which case we need
> > >to partially substitute.  */
> > > t = copy_node (t);
> > > +  REQUIRES_EXPR_EXTRA_ARGS (t) = NULL_TREE;
> > > REQUIRES_EXPR_EXTRA_ARGS (t) = build_extra_args (t, args,
> > > info.complain);
> > > return t;
> > >   }
> > > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > > index 8cf0d5b7a8d..37f2392d035 100644
> > > --- a/gcc/cp/pt.cc
> > > +++ b/gcc/cp/pt.cc
> > > @@ -18718,7 +18718,7 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t
> > > complain, tree in_decl)
> > > IF_COND (stmt) = IF_COND (t);
> > > THEN_CLAUSE (stmt) = THEN_CLAUSE (t);
> > > ELSE_CLAUSE (stmt) = ELSE_CLAUSE (t);
> > > -   IF_STMT_EXTRA_ARGS (stmt) = build_extra_args (t, args, complain);
> > > +   IF_STMT_EXTRA_ARGS (stmt) = build_extra_args (stmt, args, complain);
> > > add_stmt (stmt);
> > > break;
> > >   }
> > > diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C
> > > b/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C
> > > new file mode 100644
> > > index 000..038c2a41210
> > > --- /dev/null
> > > +++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C
> > > @@ -0,0 +1,16 @@
> > > +// PR c++/114303
> > > +// { dg-do compile { target c++17 } }
> > > +
> > > +struct A { static constexpr bool value = true; };
> > > +
> > > +int main() {
> > > +  [](auto x1) {
> > > +return [&](auto) {
> > > +  return [&](auto x3) {
> > > +if constexpr (decltype(x3)::value) {
> > > +  static_assert(decltype(x1)::value);
> > > +}
> > > +  }(A{});
> > > +}(0);
> > > +  }(A{});
> > > +}
> > 
> > 
> 



Re: [PATCH] c++: recalculating local specs via build_extra_args [PR114303]

2024-03-12 Thread Patrick Palka
On Tue, 12 Mar 2024, Jason Merrill wrote:

> On 3/11/24 12:53, Patrick Palka wrote:
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> > OK for trunk and release branches?
> > 
> > -- >8 --
> > 
> > r13-6452-g341e6cd8d603a3 made build_extra_args walk evaluated contexts
> > first so that we prefer processing a local specialization in an evaluated
> > context even if its first use is in an unevaluated context.  But this
> > means we need to avoid walking a tree that already has extra args/specs
> > saved because the list of saved specs appears to be an evaluated
> > context.  It seems then that we should be calculating the saved specs
> > from scratch each time, rather than potentially walking the saved specs
> > list from an earlier partial instantiation when calling build_extra_args
> > a second time around.
> 
> Makes sense, but I wonder if we want to approach that by avoiding walking into
> *_EXTRA_ARGS in extract_locals_r?  Or do we still want to walk into any nested
> extra args?  And if so, will we run into this same problem then?

I'm not sure totally but I'd expect a nested extra-args tree to always
have empty *_EXTRA_ARGS since the outer extra-args tree should intercept
any substitution before the inner extra-args tree can see it?

> 
> > PR c++/114303
> > 
> > gcc/cp/ChangeLog:
> > 
> > * constraint.cc (tsubst_requires_expr): Clear
> > REQUIRES_EXPR_EXTRA_ARGS before calling build_extra_args.
> > * pt.cc (tsubst_stmt) : Call build_extra_args
> > on the new IF_STMT instead of t which might already have
> > IF_STMT_EXTRA_ARGS.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/cpp1z/constexpr-if-lambda6.C: New test.
> > ---
> >   gcc/cp/constraint.cc |  1 +
> >   gcc/cp/pt.cc |  2 +-
> >   .../g++.dg/cpp1z/constexpr-if-lambda6.C  | 16 
> >   3 files changed, 18 insertions(+), 1 deletion(-)
> >   create mode 100644 gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C
> > 
> > diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> > index 49de3211d4c..8a3b5d80ba7 100644
> > --- a/gcc/cp/constraint.cc
> > +++ b/gcc/cp/constraint.cc
> > @@ -2362,6 +2362,7 @@ tsubst_requires_expr (tree t, tree args, sat_info
> > info)
> >  matching or dguide constraint rewriting), in which case we need
> >  to partially substitute.  */
> > t = copy_node (t);
> > +  REQUIRES_EXPR_EXTRA_ARGS (t) = NULL_TREE;
> > REQUIRES_EXPR_EXTRA_ARGS (t) = build_extra_args (t, args,
> > info.complain);
> > return t;
> >   }
> > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > index 8cf0d5b7a8d..37f2392d035 100644
> > --- a/gcc/cp/pt.cc
> > +++ b/gcc/cp/pt.cc
> > @@ -18718,7 +18718,7 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t
> > complain, tree in_decl)
> >   IF_COND (stmt) = IF_COND (t);
> >   THEN_CLAUSE (stmt) = THEN_CLAUSE (t);
> >   ELSE_CLAUSE (stmt) = ELSE_CLAUSE (t);
> > - IF_STMT_EXTRA_ARGS (stmt) = build_extra_args (t, args, complain);
> > + IF_STMT_EXTRA_ARGS (stmt) = build_extra_args (stmt, args, complain);
> >   add_stmt (stmt);
> >   break;
> > }
> > diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C
> > b/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C
> > new file mode 100644
> > index 000..038c2a41210
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C
> > @@ -0,0 +1,16 @@
> > +// PR c++/114303
> > +// { dg-do compile { target c++17 } }
> > +
> > +struct A { static constexpr bool value = true; };
> > +
> > +int main() {
> > +  [](auto x1) {
> > +return [&](auto) {
> > +  return [&](auto x3) {
> > +if constexpr (decltype(x3)::value) {
> > +  static_assert(decltype(x1)::value);
> > +}
> > +  }(A{});
> > +}(0);
> > +  }(A{});
> > +}
> 
> 



Re: [PATCH v2] c++: Support target-specific nodes with streaming [PR98645,PR111224]

2024-03-12 Thread Patrick Palka
On Tue, 12 Mar 2024, Nathaniel Shead wrote:

> On Tue, Mar 12, 2024 at 11:11:40PM +1100, Nathaniel Shead wrote:
> > On Mon, Mar 11, 2024 at 10:36:06AM -0400, Patrick Palka wrote:
> > > On Sun, 10 Mar 2024, Nathaniel Shead wrote:
> > > 
> > > > Bootstrapped and regtested on x86_64-pc-linux-gnu and
> > > > aarch64-unknown-linux-gnu, OK for trunk?
> > > > 
> > > > It's worth noting that the AArch64 machines I had available to test with
> > > > didn't have a new enough glibc to reproduce the ICEs in the PR, but this
> > > > patch will be necessary (albeit possibly not sufficient) to fix it.
> > > > 
> > > > -- >8 --
> > > > 
> > > > Some targets make use of POLY_INT_CSTs and other custom builtin types,
> > > > which currently violate some assumptions when streaming. This patch adds
> > > > support for them, specifically AArch64 SVE types like __fp16.
> > > 
> > > It seems other built-in types are handled by adding them to the
> > > fixed_trees vector in init_modules (and then we install them first
> > > during streaming).  Could we just add all the target-specific types to
> > > fixed_trees too?
> > > 
> > 
> > Yes, that works too. Seems cleaner as well, though I had to add it as a
> > separate loop because the set of builtin types registered is not
> > determined until runtiem (depending on e.g. ABI flags). I also noticed
> > that this fixes another PR, on PowerPC, so I've added a test for it.
> > Thanks!
> > 
> > Bootstrapped and regtested on x86_64-pc-linux-gnu,
> > aarch64-unknown-linux-gnu, and powerpc64le-unknown-linux-gnu;
> > OK for trunk?
> > 
> > -- >8 --
> > 
> > Some targets make use of POLY_INT_CSTs and other custom builtin types,
> > which currently violate some assumptions when streaming. This patch adds
> > support for them, such as types like Aarch64 __fp16, PowerPC __ibm128,
> > and vector types thereof.
> > 
> > This patch doesn't provide "full" support of AArch64 SVE, however, since
> > for that we would need to support 'target' nodes (tracked in PR108080).
> > 
> > Adding the new builtin types means that on Aarch64 we now have 217
> > global trees created on initialisation (up from 191), so this patch also
> > slightly bumps the initial size of the fixed_trees allocation to 250.
> > 
> > PR c++/98645
> > PR c++/111224
> > 
> > gcc/cp/ChangeLog:
> > 
> > * module.cc (enum tree_tag): Add new tag for builtin types.
> > (trees_out::start): POLY_INT_CSTs can be emitted.
> > (trees_in::start): Likewise.
> > (trees_out::core_vals): Stream POLY_INT_CSTs.
> > (trees_in::core_vals): Likewise.
> > (trees_out::type_node): Handle vectors with multiple coeffs.
> > (trees_in::tree_node): Likewise.
> > (init_modules): Register target-specific builtin types. Bump
> > initial capacity slightly.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/modules/target-aarch64-1_a.C: New test.
> > * g++.dg/modules/target-aarch64-1_b.C: New test.
> > * g++.dg/modules/target-powerpc-1_a.C: New test.
> > * g++.dg/modules/target-powerpc-1_b.C: New test.
> > 
> > Signed-off-by: Nathaniel Shead 
> > Reviewed-by: Patrick Palka 
> > ---
> >  gcc/cp/module.cc  | 32 +--
> >  .../g++.dg/modules/target-aarch64-1_a.C   | 17 ++
> >  .../g++.dg/modules/target-aarch64-1_b.C   | 13 
> >  .../g++.dg/modules/target-powerpc-1_a.C   |  7 
> >  .../g++.dg/modules/target-powerpc-1_b.C   | 10 ++
> >  5 files changed, 69 insertions(+), 10 deletions(-)
> >  create mode 100644 gcc/testsuite/g++.dg/modules/target-aarch64-1_a.C
> >  create mode 100644 gcc/testsuite/g++.dg/modules/target-aarch64-1_b.C
> >  create mode 100644 gcc/testsuite/g++.dg/modules/target-powerpc-1_a.C
> >  create mode 100644 gcc/testsuite/g++.dg/modules/target-powerpc-1_b.C
> > 
> > diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> > index 99055523d91..8aab9ea0bae 100644
> > --- a/gcc/cp/module.cc
> > +++ b/gcc/cp/module.cc
> > @@ -5173,7 +5173,6 @@ trees_out::start (tree t, bool code_streamed)
> >break;
> >  
> >  case FIXED_CST:
> > -case POLY_INT_CST:
> >gcc_unreachable (); /* Not supported in C++.  */
> >break;
> >  
> > @@ -5259,7 +5258,6 @@ trees_in::start (unsigned code)
> >  
> >  case FIXED_CST:
&

[PATCH] c++: recalculating local specs via build_extra_args [PR114303]

2024-03-11 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
OK for trunk and release branches?

-- >8 --

r13-6452-g341e6cd8d603a3 made build_extra_args walk evaluated contexts
first so that we prefer processing a local specialization in an evaluated
context even if its first use is in an unevaluated context.  But this
means we need to avoid walking a tree that already has extra args/specs
saved because the list of saved specs appears to be an evaluated
context.  It seems then that we should be calculating the saved specs
from scratch each time, rather than potentially walking the saved specs
list from an earlier partial instantiation when calling build_extra_args
a second time around.

PR c++/114303

gcc/cp/ChangeLog:

* constraint.cc (tsubst_requires_expr): Clear
REQUIRES_EXPR_EXTRA_ARGS before calling build_extra_args.
* pt.cc (tsubst_stmt) : Call build_extra_args
on the new IF_STMT instead of t which might already have
IF_STMT_EXTRA_ARGS.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/constexpr-if-lambda6.C: New test.
---
 gcc/cp/constraint.cc |  1 +
 gcc/cp/pt.cc |  2 +-
 .../g++.dg/cpp1z/constexpr-if-lambda6.C  | 16 
 3 files changed, 18 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 49de3211d4c..8a3b5d80ba7 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -2362,6 +2362,7 @@ tsubst_requires_expr (tree t, tree args, sat_info info)
 matching or dguide constraint rewriting), in which case we need
 to partially substitute.  */
   t = copy_node (t);
+  REQUIRES_EXPR_EXTRA_ARGS (t) = NULL_TREE;
   REQUIRES_EXPR_EXTRA_ARGS (t) = build_extra_args (t, args, info.complain);
   return t;
 }
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 8cf0d5b7a8d..37f2392d035 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -18718,7 +18718,7 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
  IF_COND (stmt) = IF_COND (t);
  THEN_CLAUSE (stmt) = THEN_CLAUSE (t);
  ELSE_CLAUSE (stmt) = ELSE_CLAUSE (t);
- IF_STMT_EXTRA_ARGS (stmt) = build_extra_args (t, args, complain);
+ IF_STMT_EXTRA_ARGS (stmt) = build_extra_args (stmt, args, complain);
  add_stmt (stmt);
  break;
}
diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C 
b/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C
new file mode 100644
index 000..038c2a41210
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C
@@ -0,0 +1,16 @@
+// PR c++/114303
+// { dg-do compile { target c++17 } }
+
+struct A { static constexpr bool value = true; };
+
+int main() {
+  [](auto x1) {
+return [&](auto) {
+  return [&](auto x3) {
+if constexpr (decltype(x3)::value) {
+  static_assert(decltype(x1)::value);
+}
+  }(A{});
+}(0);
+  }(A{});
+}
-- 
2.44.0.165.ge09f1254c5



Re: [PATCH] c++/modules: Support target-specific nodes with streaming [PR111224]

2024-03-11 Thread Patrick Palka
On Sun, 10 Mar 2024, Nathaniel Shead wrote:

> Bootstrapped and regtested on x86_64-pc-linux-gnu and
> aarch64-unknown-linux-gnu, OK for trunk?
> 
> It's worth noting that the AArch64 machines I had available to test with
> didn't have a new enough glibc to reproduce the ICEs in the PR, but this
> patch will be necessary (albeit possibly not sufficient) to fix it.
> 
> -- >8 --
> 
> Some targets make use of POLY_INT_CSTs and other custom builtin types,
> which currently violate some assumptions when streaming. This patch adds
> support for them, specifically AArch64 SVE types like __fp16.

It seems other built-in types are handled by adding them to the
fixed_trees vector in init_modules (and then we install them first
during streaming).  Could we just add all the target-specific types to
fixed_trees too?

> 
> This patch doesn't provide "full" support of AArch64 SVE, however, since
> for that we would need to support 'target' nodes (tracked in PR108080).
> 
>   PR c++/111224
> 
> gcc/cp/ChangeLog:
> 
>   * module.cc (enum tree_tag): Add new tag for builtin types.
>   (trees_out::start): POLY_INT_CSTs can be emitted.
>   (trees_in::start): Likewise.
>   (trees_out::core_vals): Stream POLY_INT_CSTs.
>   (trees_in::core_vals): Likewise.
>   (trees_out::type_node): Handle target-specific builtin types,
>   and vectors with NUM_POLY_INT_COEFFS > 1.
>   (trees_in::tree_node): Likewise.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/modules/pr111224_a.C: New test.
>   * g++.dg/modules/pr111224_b.C: New test.
> 
> Signed-off-by: Nathaniel Shead 
> ---
>  gcc/cp/module.cc  | 70 +++
>  gcc/testsuite/g++.dg/modules/pr111224_a.C | 17 ++
>  gcc/testsuite/g++.dg/modules/pr111224_b.C | 13 +
>  3 files changed, 90 insertions(+), 10 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/modules/pr111224_a.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/pr111224_b.C
> 
> diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> index 99055523d91..0b5e2e67053 100644
> --- a/gcc/cp/module.cc
> +++ b/gcc/cp/module.cc
> @@ -2718,6 +2718,7 @@ enum tree_tag {
>tt_typedef_type,   /* A (possibly implicit) typedefed type.  */
>tt_derived_type,   /* A type derived from another type.  */
>tt_variant_type,   /* A variant of another type.  */
> +  tt_builtin_type,  /* A custom builtin type.  */
>  
>tt_tinfo_var,  /* Typeinfo object. */
>tt_tinfo_typedef,  /* Typeinfo typedef.  */
> @@ -2732,7 +2733,7 @@ enum tree_tag {
>tt_binfo,  /* A BINFO.  */
>tt_vtable, /* A vtable.  */
>tt_thunk,  /* A thunk.  */
> -  tt_clone_ref,
> +  tt_clone_ref, /* A cloned function.  */
>  
>tt_entity, /* A extra-cluster entity.  */
>  
> @@ -5173,7 +5174,6 @@ trees_out::start (tree t, bool code_streamed)
>break;
>  
>  case FIXED_CST:
> -case POLY_INT_CST:
>gcc_unreachable (); /* Not supported in C++.  */
>break;
>  
> @@ -5259,7 +5259,6 @@ trees_in::start (unsigned code)
>  
>  case FIXED_CST:
>  case IDENTIFIER_NODE:
> -case POLY_INT_CST:
>  case SSA_NAME:
>  case TARGET_MEM_REF:
>  case TRANSLATION_UNIT_DECL:
> @@ -6106,7 +6105,10 @@ trees_out::core_vals (tree t)
>break;
>  
>  case POLY_INT_CST:
> -  gcc_unreachable (); /* Not supported in C++.  */
> +  if (streaming_p ())
> + for (unsigned ix = 0; ix != NUM_POLY_INT_COEFFS; ix++)
> +   WT (POLY_INT_CST_COEFF (t, ix));
> +  break;
>  
>  case REAL_CST:
>if (streaming_p ())
> @@ -6615,8 +6617,9 @@ trees_in::core_vals (tree t)
>break;
>  
>  case POLY_INT_CST:
> -  /* Not suported in C++.  */
> -  return false;
> +  for (unsigned ix = 0; ix != NUM_POLY_INT_COEFFS; ix++)
> + RT (POLY_INT_CST_COEFF (t, ix));
> +  break;
>  
>  case REAL_CST:
>if (const void *bytes = buf (sizeof (real_value)))
> @@ -8930,6 +8933,32 @@ trees_out::type_node (tree type)
>return;
>  }
>  
> +  if (tree name = TYPE_NAME (type))
> +if (TREE_CODE (name) == TYPE_DECL && DECL_ARTIFICIAL (name))
> +  {
> + /* Potentially a custom machine- or OS-specific builtin type.  */
> + bool found = false;
> + unsigned ix = 0;
> + for (tree t = registered_builtin_types; t; t = TREE_CHAIN (t), ix++)
> +   if (TREE_VALUE (t) == type)
> + {
> +   found = true;
> +   break;
> + }
> + if (found)
> +   {
> + int type_tag = insert (type);
> + if (streaming_p ())
> +   {
> + i (tt_builtin_type);
> + u (ix);
> + dump (dumper::TREE)
> +   && dump ("Wrote:%d builtin type %N", type_tag, name);
> +   }
> + return;
> +   }
> +  }
> +
>if (streaming_p ())
>  {
>u (tt_derived_type);
> @@ -9068,8 +9097,8 @@ trees_out::type_node (tree type)
>

Re: [PATCH v14 26/26] libstdc++: Optimize std::is_nothrow_invocable compilation performance

2024-03-08 Thread Patrick Palka
On Wed, 28 Feb 2024, Ken Matsui wrote:

> This patch optimizes the compilation performance of
> std::is_nothrow_invocable by dispatching to the new
> __is_nothrow_invocable built-in trait.
> 
> libstdc++-v3/ChangeLog:
> 
>   * include/std/type_traits (is_nothrow_invocable): Use
>   __is_nothrow_invocable built-in trait.
>   * testsuite/20_util/is_nothrow_invocable/incomplete_args_neg.cc:
>   Handle the new error from __is_nothrow_invocable.
>   * testsuite/20_util/is_nothrow_invocable/incomplete_neg.cc:
>   Likewise.
> 
> Signed-off-by: Ken Matsui 
> ---
>  libstdc++-v3/include/std/type_traits  | 4 
>  .../20_util/is_nothrow_invocable/incomplete_args_neg.cc   | 1 +
>  .../testsuite/20_util/is_nothrow_invocable/incomplete_neg.cc  | 1 +
>  3 files changed, 6 insertions(+)
> 
> diff --git a/libstdc++-v3/include/std/type_traits 
> b/libstdc++-v3/include/std/type_traits
> index 9af233bcc75..093d85a51a8 100644
> --- a/libstdc++-v3/include/std/type_traits
> +++ b/libstdc++-v3/include/std/type_traits
> @@ -3265,8 +3265,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>/// std::is_nothrow_invocable
>template
>  struct is_nothrow_invocable
> +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_nothrow_invocable)
> +: public __bool_constant<__is_nothrow_invocable(_Fn, _ArgTypes...)>
> +#else
>  : __and_<__is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, void>,
>__call_is_nothrow_<_Fn, _ArgTypes...>>::type
> +#endif
>  {
>static_assert(std::__is_complete_or_unbounded(__type_identity<_Fn>{}),
>   "_Fn must be a complete class or an unbounded array");
> diff --git 
> a/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/incomplete_args_neg.cc 
> b/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/incomplete_args_neg.cc
> index 3c225883eaf..3f8542dd366 100644
> --- 
> a/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/incomplete_args_neg.cc
> +++ 
> b/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/incomplete_args_neg.cc
> @@ -18,6 +18,7 @@
>  // .
>  
>  // { dg-error "must be a complete class" "" { target *-*-* } 0 }
> +// { dg-prune-output "invalid use of incomplete type" }

Is the error coming somewhere from the new build_invoke function?  That'd
be surprising since we pass tf_none to it, which should suppress such
errors.  (You can probably break on cxx_incomplete_type_diagnostic to
find out where it's coming from.)

>  
>  #include 
>  
> diff --git 
> a/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/incomplete_neg.cc 
> b/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/incomplete_neg.cc
> index 5a728bfa03b..d3bdf08448b 100644
> --- a/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/incomplete_neg.cc
> +++ b/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/incomplete_neg.cc
> @@ -18,6 +18,7 @@
>  // .
>  
>  // { dg-error "must be a complete class" "" { target *-*-* } 0 }
> +// { dg-prune-output "invalid use of incomplete type" }
>  
>  #include 
>  
> -- 
> 2.44.0
> 
> 



Re: [PATCH v14 23/26] c++: Implement __is_invocable built-in trait

2024-03-08 Thread Patrick Palka
On Wed, 28 Feb 2024, Ken Matsui wrote:

> This patch implements built-in trait for std::is_invocable.
> 
> gcc/cp/ChangeLog:
> 
>   * cp-trait.def: Define __is_invocable.
>   * constraint.cc (diagnose_trait_expr): Handle CPTK_IS_INVOCABLE.
>   * semantics.cc (trait_expr_value): Likewise.
>   (finish_trait_expr): Likewise.
>   * cp-tree.h (build_invoke): New function.
>   * method.cc (build_invoke): New function.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/ext/has-builtin-1.C: Test existence of __is_invocable.
>   * g++.dg/ext/is_invocable1.C: New test.
>   * g++.dg/ext/is_invocable2.C: New test.
>   * g++.dg/ext/is_invocable3.C: New test.
>   * g++.dg/ext/is_invocable4.C: New test.

Thanks, this looks great!  This generic build_invoke function could be
used for invoke_result etc as well, and it could also cache the built-up
call across __is_invocable and __is_nothrow_invocable checks on the same
arguments (which is a common pattern in the standard library).  LGTM

> 
> Signed-off-by: Ken Matsui 
> ---
>  gcc/cp/constraint.cc |   6 +
>  gcc/cp/cp-trait.def  |   1 +
>  gcc/cp/cp-tree.h |   2 +
>  gcc/cp/method.cc | 132 +
>  gcc/cp/semantics.cc  |   4 +
>  gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
>  gcc/testsuite/g++.dg/ext/is_invocable1.C | 349 +++
>  gcc/testsuite/g++.dg/ext/is_invocable2.C | 139 +
>  gcc/testsuite/g++.dg/ext/is_invocable3.C |  51 
>  gcc/testsuite/g++.dg/ext/is_invocable4.C |  33 +++
>  10 files changed, 720 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable1.C
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable2.C
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable3.C
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable4.C
> 
> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> index 23ea66d9c12..c87b126fdb1 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -3791,6 +3791,12 @@ diagnose_trait_expr (tree expr, tree args)
>  case CPTK_IS_FUNCTION:
>inform (loc, "  %qT is not a function", t1);
>break;
> +case CPTK_IS_INVOCABLE:
> +  if (!t2)
> +inform (loc, "  %qT is not invocable", t1);
> +  else
> +inform (loc, "  %qT is not invocable by %qE", t1, t2);
> +  break;
>  case CPTK_IS_LAYOUT_COMPATIBLE:
>inform (loc, "  %qT is not layout compatible with %qT", t1, t2);
>break;
> diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
> index 85056c8140b..6cb2b55f4ea 100644
> --- a/gcc/cp/cp-trait.def
> +++ b/gcc/cp/cp-trait.def
> @@ -75,6 +75,7 @@ DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
>  DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
>  DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
>  DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
> +DEFTRAIT_EXPR (IS_INVOCABLE, "__is_invocable", -1)
>  DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
>  DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
>  DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 334c11396c2..261d3a71faa 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -7334,6 +7334,8 @@ extern tree get_copy_assign (tree);
>  extern tree get_default_ctor (tree);
>  extern tree get_dtor (tree, tsubst_flags_t);
>  extern tree build_stub_object(tree);
> +extern tree build_invoke (tree, const_tree,
> +  tsubst_flags_t);
>  extern tree strip_inheriting_ctors   (tree);
>  extern tree inherited_ctor_binfo (tree);
>  extern bool base_ctor_omit_inherited_parms   (tree);
> diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc
> index 98c10e6a8b5..953f1bed6fc 100644
> --- a/gcc/cp/method.cc
> +++ b/gcc/cp/method.cc
> @@ -1928,6 +1928,138 @@ build_trait_object (tree type)
>return build_stub_object (type);
>  }
>  
> +/* [func.require] Build an expression of INVOKE(FN_TYPE, ARG_TYPES...).  If 
> the
> +   given is not invocable, returns error_mark_node.  */
> +
> +tree
> +build_invoke (tree fn_type, const_tree arg_types, tsubst_flags_t complain)
> +{
> +  if (fn_type == error_mark_node || arg_types == error_mark_node)
> +return error_mark_node;
> +
> +  gcc_assert (TYPE_P (fn_type));
> +  gcc_assert (TREE_CODE (arg_types) == TREE_VEC);
> +
> +  /* Access check is required to determine if the given is invocable.  */
> +  deferring_access_check_sentinel acs (dk_no_deferred);
> +
> +  /* INVOKE is an unevaluated context.  */
> +  cp_unevaluated cp_uneval_guard;
> +
> +  bool is_ptrdatamem;
> +  bool is_ptrmemfunc;
> +  if (TREE_CODE (fn_type) == REFERENCE_TYPE)
> +{
> +  tree deref_fn_type = TREE_TYPE (fn_type);
> +  is_ptrdatamem = 

  1   2   3   4   5   6   7   8   9   10   >