[PATCH] c++: [[deprecated]] on template redecl [PR84542]

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

-- >8 --

The deprecated and unavailable attributes weren't working when used on
a template redeclaration ultimately because the corresponding tree flags
on the underlying decls weren't being merged across redeclarations.

PR c++/84542

gcc/cp/ChangeLog:

* decl.cc (merge_attribute_bits):

gcc/testsuite/ChangeLog:

* g++.dg/ext/attr-deprecated-2.C: No longer XFAIL.
* g++.dg/ext/attr-unavailable-12.C: New test.
---
 gcc/cp/decl.cc |  5 -
 gcc/testsuite/g++.dg/ext/attr-deprecated-2.C   |  4 ++--
 gcc/testsuite/g++.dg/ext/attr-unavailable-12.C | 12 
 3 files changed, 18 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/attr-unavailable-12.C

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 1ffe4c82748..36375ea3c14 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -1530,6 +1530,10 @@ merge_attribute_bits (tree newdecl, tree olddecl)
   DECL_PURE_P (olddecl) |= DECL_PURE_P (newdecl);
   DECL_UNINLINABLE (newdecl) |= DECL_UNINLINABLE (olddecl);
   DECL_UNINLINABLE (olddecl) |= DECL_UNINLINABLE (newdecl);
+  TREE_DEPRECATED (newdecl) |= TREE_DEPRECATED (olddecl);
+  TREE_DEPRECATED (olddecl) |= TREE_DEPRECATED (newdecl);
+  TREE_UNAVAILABLE (newdecl) |= TREE_UNAVAILABLE (olddecl);
+  TREE_UNAVAILABLE (olddecl) |= TREE_UNAVAILABLE (newdecl);
 }
 
 #define GNU_INLINE_P(fn) (DECL_DECLARED_INLINE_P (fn)  \
@@ -1542,7 +1546,6 @@ merge_attribute_bits (tree newdecl, tree olddecl)
 static bool
 duplicate_function_template_decls (tree newdecl, tree olddecl)
 {
-
   tree newres = DECL_TEMPLATE_RESULT (newdecl);
   tree oldres = DECL_TEMPLATE_RESULT (olddecl);
   /* Function template declarations can be differentiated by parameter
diff --git a/gcc/testsuite/g++.dg/ext/attr-deprecated-2.C 
b/gcc/testsuite/g++.dg/ext/attr-deprecated-2.C
index bf9041506d1..6f6c210ddb5 100644
--- a/gcc/testsuite/g++.dg/ext/attr-deprecated-2.C
+++ b/gcc/testsuite/g++.dg/ext/attr-deprecated-2.C
@@ -23,8 +23,8 @@ fdeprecated_primary ();
 void use_primary ()
 {
   // Verify that uses of the now deprecacted primary are diagnosed.
-  fdeprecated_primary();  // { dg-warning "deprecated" "bug 
84542" { xfail *-*-* } }
-  fdeprecated_primary();   // { dg-warning "deprecated" "bug 
84542" { xfail *-*-* } }
+  fdeprecated_primary();  // { dg-warning "deprecated" "bug 
84542" }
+  fdeprecated_primary();   // { dg-warning "deprecated" "bug 
84542" }
 }
 
 void use_special ()
diff --git a/gcc/testsuite/g++.dg/ext/attr-unavailable-12.C 
b/gcc/testsuite/g++.dg/ext/attr-unavailable-12.C
new file mode 100644
index 000..7174abc8bb9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/attr-unavailable-12.C
@@ -0,0 +1,12 @@
+// PR c++/84542
+
+template
+void f(T);
+
+template
+__attribute__((unavailable))
+void f(T) { }
+
+int main() {
+  f(0); // { dg-error "unavailable" }
+}
-- 
2.43.0.76.g1a87c842ec



Re: [PATCH] libstdc++: Make __gnu_debug::vector usable in constant expressions [PR109536]

2023-12-16 Thread Patrick Palka
On Sat, 16 Dec 2023, Jonathan Wakely wrote:

> On Sat, 16 Dec 2023 at 09:14, Jonathan Wakely wrote:
> >
> > On Sat, 16 Dec 2023 at 00:27, Patrick Palka wrote:
> > >
> > > On Wed, 6 Dec 2023, Jonathan Wakely wrote:
> > >
> > > > Any comments on this approach?
> > > >
> > > > -- >8 --
> > > >
> > > > This makes constexpr std::vector (mostly) work in Debug Mode. All safe
> > > > iterator instrumentation and checking is disabled during constant
> > > > evaluation, because it requires mutex locks and calls to non-inline
> > > > functions defined in libstdc++.so. It should be OK to disable the safety
> > > > checks, because most UB should be detected during constant evaluation
> > > > anyway.
> > > >
> > > > We could try to enable the full checking in constexpr, but it would mean
> > > > wrapping all the non-inline functions like _M_attach with an inline
> > > > _M_constexpr_attach that does the iterator housekeeping inline without
> > > > mutex locks when calling for constant evaluation, and calls the
> > > > non-inline function at runtime. That could be done in future if we find
> > > > that we've lost safety or useful checking by disabling the safe
> > > > iterators.
> > > >
> > > > There are a few test failures in C++20 mode, which I'm unable to
> > > > explain. The _Safe_iterator::operator++() member gives errors for using
> > > > non-constexpr functions during constant evaluation, even though those
> > > > functions are guarded by std::is_constant_evaluated() checks. The same
> > > > code works fine for C++23 and up.
> > >
> > > AFAICT these C++20 test failures are really due to the variable
> > > definition of non-literal type
> > >
> > > 381__gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
> > >
> > > which were prohibited in a constexpr function (even if that code was
> > > never executed) until C++23's P2242R3.
> >
> > Ah, I figured it was a core change but I couldn't recall which one. Thanks.

Yeah the diagnostic blaming the non-constexpr call to _M_incrementable
was outright wrong and misleading, I filed PR113041 about that.

> >
> > > We can use an immediately invoked lambda to work around this:
> > >
> > > 381[this] {
> > > 382  __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
> > > 383  ++base();
> > > 384}();
> > > 385return *this;
> >
> > We'd need some #if as this code has to work for C++98. But that's doable.
> 
> The attached patch seems simpler, I'm testing it now.

Would the operator+=, operator-= and the copy assign operator= also need
adjustment?

We could somewhat cleanly encapsulate the lambda workaround with a pair
of macros surrounding the problematic variable, something like:

diff --git a/libstdc++-v3/include/debug/safe_iterator.h 
b/libstdc++-v3/include/debug/safe_iterator.h
index 26f008982f8..df3b4d33f04 100644
--- a/libstdc++-v3/include/debug/safe_iterator.h
+++ b/libstdc++-v3/include/debug/safe_iterator.h
@@ -360,6 +360,14 @@ namespace __gnu_debug
return base().operator->();
   }
 
+#if __cplusplus >= 202002L && __cpp_constexpr < 202110L
+# define _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_BEGIN [&] { do
+# define _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_END while(false); }()
+#else
+# define _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_BEGIN do
+# define _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_END while(false)
+#endif
+
   // -- Input iterator requirements --
   /**
*  @brief Iterator preincrement
@@ -378,8 +386,10 @@ namespace __gnu_debug
_GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
  _M_message(__msg_bad_inc)
  ._M_iterator(*this, "this"));
-   __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
-   ++base();
+   _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_BEGIN {
+ __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
+ ++base();
+   } _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_END;
return *this;
   }
 



Re: [PATCH] libstdc++: Make __gnu_debug::vector usable in constant expressions [PR109536]

2023-12-15 Thread Patrick Palka
On Wed, 6 Dec 2023, Jonathan Wakely wrote:

> Any comments on this approach?
> 
> -- >8 --
> 
> This makes constexpr std::vector (mostly) work in Debug Mode. All safe
> iterator instrumentation and checking is disabled during constant
> evaluation, because it requires mutex locks and calls to non-inline
> functions defined in libstdc++.so. It should be OK to disable the safety
> checks, because most UB should be detected during constant evaluation
> anyway.
> 
> We could try to enable the full checking in constexpr, but it would mean
> wrapping all the non-inline functions like _M_attach with an inline
> _M_constexpr_attach that does the iterator housekeeping inline without
> mutex locks when calling for constant evaluation, and calls the
> non-inline function at runtime. That could be done in future if we find
> that we've lost safety or useful checking by disabling the safe
> iterators.
> 
> There are a few test failures in C++20 mode, which I'm unable to
> explain. The _Safe_iterator::operator++() member gives errors for using
> non-constexpr functions during constant evaluation, even though those
> functions are guarded by std::is_constant_evaluated() checks. The same
> code works fine for C++23 and up.

AFAICT these C++20 test failures are really due to the variable
definition of non-literal type

381__gnu_cxx::__scoped_lock __l(this->_M_get_mutex());

which were prohibited in a constexpr function (even if that code was
never executed) until C++23's P2242R3.

We can use an immediately invoked lambda to work around this:

381[this] {
382  __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
383  ++base();
384}();
385return *this;

> 
> libstdc++-v3/ChangeLog:
> 
>   PR libstdc++/109536
>   * include/bits/c++config (__glibcxx_constexpr_assert): Remove
>   macro.
>   * include/bits/stl_algobase.h (__niter_base, __copy_move_a)
>   (__copy_move_backward_a, __fill_a, __fill_n_a, __equal_aux)
>   (__lexicographical_compare_aux): Add constexpr to overloads for
>   debug mode iterators.
>   * include/debug/helper_functions.h (__unsafe): Add constexpr.
>   * include/debug/macros.h (_GLIBCXX_DEBUG_VERIFY_COND_AT): Remove
>   macro, folding it into ...
>   (_GLIBCXX_DEBUG_VERIFY_AT_F): ... here. Do not use
>   __glibcxx_constexpr_assert.
>   * include/debug/safe_base.h (_Safe_iterator_base): Add constexpr
>   to some member functions. Omit attaching, detaching and checking
>   operations during constant evaluation.
>   * include/debug/safe_container.h (_Safe_container): Likewise.
>   * include/debug/safe_iterator.h (_Safe_iterator): Likewise.
>   * include/debug/safe_iterator.tcc (__niter_base, __copy_move_a)
>   (__copy_move_backward_a, __fill_a, __fill_n_a, __equal_aux)
>   (__lexicographical_compare_aux): Add constexpr.
>   * include/debug/vector (_Safe_vector, vector): Add constexpr.
>   Omit safe iterator operations during constant evaluation.
>   * testsuite/23_containers/vector/bool/capacity/constexpr.cc:
>   Remove dg-xfail-if for debug mode.
>   * testsuite/23_containers/vector/bool/cmp_c++20.cc: Likewise.
>   * testsuite/23_containers/vector/bool/cons/constexpr.cc:
>   Likewise.
>   * testsuite/23_containers/vector/bool/element_access/1.cc:
>   Likewise.
>   * testsuite/23_containers/vector/bool/element_access/constexpr.cc:
>   Likewise.
>   * testsuite/23_containers/vector/bool/modifiers/assign/constexpr.cc:
>   Likewise.
>   * testsuite/23_containers/vector/bool/modifiers/constexpr.cc:
>   Likewise.
>   * testsuite/23_containers/vector/bool/modifiers/swap/constexpr.cc:
>   Likewise.
>   * testsuite/23_containers/vector/capacity/constexpr.cc:
>   Likewise.
>   * testsuite/23_containers/vector/cmp_c++20.cc: Likewise.
>   * testsuite/23_containers/vector/cons/constexpr.cc: Likewise.
>   * testsuite/23_containers/vector/data_access/constexpr.cc:
>   Likewise.
>   * testsuite/23_containers/vector/element_access/constexpr.cc:
>   Likewise.
>   * testsuite/23_containers/vector/modifiers/assign/constexpr.cc:
>   Likewise.
>   * testsuite/23_containers/vector/modifiers/constexpr.cc:
>   Likewise.
>   * testsuite/23_containers/vector/modifiers/swap/constexpr.cc:
>   Likewise.
> ---
>  libstdc++-v3/include/bits/c++config   |   9 -
>  libstdc++-v3/include/bits/stl_algobase.h  |  15 ++
>  libstdc++-v3/include/debug/helper_functions.h |   1 +
>  libstdc++-v3/include/debug/macros.h   |   9 +-
>  libstdc++-v3/include/debug/safe_base.h|  35 +++-
>  libstdc++-v3/include/debug/safe_container.h   |  15 +-
>  libstdc++-v3/include/debug/safe_iterator.h| 186 +++---
>  libstdc++-v3/include/debug/safe_iterator.tcc  |  15 ++
>  libstdc++-v3/include/debug/vector | 146 --
>  .../vector/bool/capacity/constexpr.cc |   1 -
>  

Re: [PATCH 2/2] c++: partial ordering and dep alias tmpl specs [PR90679]

2023-12-15 Thread Patrick Palka
On Thu, 1 Jun 2023, Patrick Palka wrote:

> During partial ordering, we want to look through dependent alias
> template specializations within template arguments and otherwise
> treat them as opaque in other contexts (see e.g. r7-7116-g0c942f3edab108
> and r11-7011-g6e0a231a4aa240).  To that end template_args_equal was
> given a partial_order flag that controls this behavior.  This flag
> does the right thing when a dependent alias template specialization
> appears as template argument of the partial specialization, e.g. in
> 
>   template using first_t = T;
>   template struct traits;
>   template struct traits> { }; // #1
>   template struct traits> { }; // #2
> 
> we correctly consider #2 to be more specialized than #1.  But if
> the alias specialization appears as a template argument of another
> class template specialization, e.g. in
> 
>   template struct traits>> { }; // #1
>   template struct traits>> { }; // #2
> 
> then we incorrectly consider #1 and #2 to be unordered.  This is because
> 
>   1. we don't propagate the flag to recursive template_args_equal calls
>   2. we don't use structural equality for class template specializations
>  written in terms of dependent alias template specializations
> 
> This patch fixes the first issue by turning the partial_order flag into
> a global.  This patch fixes the second issue by making us propagate
> structural equality appropriately when building a class template
> specialization.  In passing this patch also improves hashing of
> specializations that use structural equality.
> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk?
> 
>   PR c++/90679
> 
> gcc/cp/ChangeLog:
> 
>   * cp-tree.h (comp_template_args): Remove partial_order
>   parameter.
>   (template_args_equal): Likewise.
>   * pt.cc (iterative_hash_template_arg) : Hash
>   the template and arguments for specializations that use
>   structural equality.
>   (comparing_for_partial_ordering): New flag.
>   (template_args_equal): Remove partial order parameter and
>   use comparing_for_partial_ordering instead.
>   (comp_template_args): Likewise.
>   (comp_template_args_porder): Set comparing_for_partial_ordering
>   instead.  Make static.
>   (any_template_arguments_need_structural_equality_p): Return true
>   for an argument that's a dependent alias template specialization
>   or a class template specialization that itself needs structural
>   equality.
>   * tree.cc (cp_tree_equal) : Adjust call to
>   comp_template_args.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp0x/alias-decl-75a.C: New test.
>   * g++.dg/cpp0x/alias-decl-75b.C: New test.

Ping.  Here's the rebased patch:

-- >8 --

Subject: [PATCH 2/2] c++: partial ordering and dep alias tmpl specs [PR90679]

During partial ordering, we want to look through dependent alias
template specializations within template arguments and otherwise
treat them as opaque in other contexts (see e.g. r7-7116-g0c942f3edab108
and r11-7011-g6e0a231a4aa240).  To that end template_args_equal was
given a partial_order flag that controls this behavior.  This flag
does the right thing when a dependent alias template specialization
appears as template argument of the partial specialization, e.g. in

  template using first_t = T;
  template struct traits;
  template struct traits> { }; // #1
  template struct traits> { }; // #2

we correctly consider #2 to be more specialized than #1.  But if
the alias specialization appears as a template argument of another
class template specialization, e.g. in

  template struct traits>> { }; // #1
  template struct traits>> { }; // #2

then we incorrectly consider #1 and #2 to be unordered.  This is because

  1. we don't propagate the flag to recursive template_args_equal calls
  2. we don't use structural equality for class template specializations
 written in terms of dependent alias template specializations

This patch fixes the first issue by turning the partial_order flag into
a global.  This patch fixes the second issue by making us propagate
structural equality appropriately when building a class template
specialization.  In passing this patch also improves hashing of
specializations that use structural equality.

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

PR c++/90679

gcc/cp/ChangeLog:

* cp-tree.h (comp_template_args): Remove partial_order
parameter.
(template_args_equal): Likewise.
* pt.cc (iterative_hash_template_arg) : Hash
the template and arguments for specializations that use
structural equality.
(comparing_for_partial_ordering): New flag.
(template_ar

Re: [PATCH 1/2] c++: refine dependent_alias_template_spec_p [PR90679]

2023-12-15 Thread Patrick Palka
On Mon, 11 Sep 2023, Patrick Palka wrote:

> On Thu, 1 Jun 2023, Patrick Palka wrote:
> 
> > For a complex alias template-id, dependent_alias_template_spec_p returns
> > true if any template argument of the template-id is dependent.  This
> > predicate indicates that substitution into the template-id may behave
> > differently with respect to SFINAE than substitution into the expanded
> > alias, and so the alias is in a way non-transparent.  For example
> > 'first_t' in
> > 
> >   template using first_t = T;
> >   template first_t f();
> > 
> > is such an alias template-id since first_t doesn't use its second
> > template parameter and so the substitution into the expanded alias would
> > discard the SFINAE effects of the corresponding (dependent) argument 'T&'.
> > 
> > But this predicate is overly conservative since what really matters for
> > sake of SFINAE equivalence is whether a template argument corresponding
> > to an _unused_ template parameter is dependent.  So the predicate should
> > return false for e.g. 'first_t' or 'first_t'.
> > 
> > This patch refines the predicate appropriately.  We need to be able to
> > efficiently determine which template parameters of a complex alias
> > template are unused, so to that end we add a new out parameter to
> > complex_alias_template_p and cache its result in an on-the-side
> > hash_map that replaces the existing TEMPLATE_DECL_COMPLEX_ALIAS_P
> > flag.  And in doing so, we fix a latent bug that this flag wasn't
> > being propagated during partial instantiation, and so we were treating
> > all partially instantiated member alias templates as non-complex.
> > 
> > PR c++/90679
> > 
> > gcc/cp/ChangeLog:
> > 
> > * cp-tree.h (TEMPLATE_DECL_COMPLEX_ALIAS_P): Remove.
> > (most_general_template): Constify parameter.
> > * pt.cc (push_template_decl): Adjust after removing
> > TEMPLATE_DECL_COMPLEX_ALIAS_P.
> > (complex_alias_tmpl_info): New hash_map.
> > (uses_all_template_parms_data::seen): Change type to
> > tree* from bool*.
> > (complex_alias_template_r): Adjust accordingly.
> > (complex_alias_template_p): Add 'seen_out' out parameter.
> > Call most_general_template and check PRIMARY_TEMPLATE_P.
> > Use complex_alias_tmpl_info to cache the result and set
> > '*seen_out' accordigly.
> > (dependent_alias_template_spec_p): Add !processing_template_decl
> > early exit test.  Consider dependence of only template arguments
> > corresponding to seen template parameters as per
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/cpp0x/alias-decl-75.C: New test.
> 
> Ping.

Ping.  Here's a rebased patch:

-- >8 --

Subject: [PATCH 1/2] c++: refine dependent_alias_template_spec_p [PR90679]

For a (complex) alias template-id, dependent_alias_template_spec_p
returns true if any template argument of the template-id is dependent.
This predicate indicates that substitution into the template-id may
behave differently with respect to SFINAE than substitution into the
expanded alias, and so the alias is in a way non-transparent.

For example, 'first_t' in

  template using first_t = T;
  template first_t f();

is such an alias template-id since first_t doesn't use its second
template parameter and so the substitution into the expanded alias would
discard the SFINAE effects of the corresponding (dependent) argument 'T&'.

But this predicate is overly conservative since what really matters for
sake of SFINAE equivalence is whether a template argument corresponding
to an _unused_ template parameter is dependent.  So the predicate should
return false for e.g. 'first_t'.

This patch refines the predicate appropriately.  We need to be able to
efficiently determine which template parameters of a complex alias
template are unused, so to that end we add a new out parameter to
complex_alias_template_p and cache its result in an on-the-side
hash_map that replaces the existing TEMPLATE_DECL_COMPLEX_ALIAS_P
flag.

PR c++/90679

gcc/cp/ChangeLog:

* cp-tree.h (TEMPLATE_DECL_COMPLEX_ALIAS_P): Remove.
(most_general_template): Constify parameter.
* pt.cc (push_template_decl): Adjust after removing
TEMPLATE_DECL_COMPLEX_ALIAS_P.
(complex_alias_tmpl_info): New hash_map.
(uses_all_template_parms_data::seen): Change type to
tree* from bool*.
(complex_alias_template_r): Adjust accordingly.
(complex_alias_template_p): Add 'seen_out' out parameter.
Call most_general_template and check PRIMARY_TEMPLATE_P.
Use complex_alias_tmpl_info to cache the result and set
'*seen_out' accordigly.
(dependent_al

Re: [PATCH] c++: abi_tag attribute on templates [PR109715]

2023-12-14 Thread Patrick Palka
On Thu, 14 Dec 2023, Jason Merrill wrote:

> On 12/14/23 16:08, Patrick Palka wrote:
> > On Thu, 14 Dec 2023, Jason Merrill wrote:
> > 
> > > On 12/14/23 14:17, Patrick Palka wrote:
> > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > > > trunk?  Do we want to condition this on abi_check (19)?
> > > 
> > > I think we do, sadly.
> > 
> > Sounds good, like so?  Bootstrap and regtest in progress.
> > 
> > -- >8 --
> > 
> > Subject: [PATCH] c++: abi_tag attribute on templates [PR109715]
> > 
> > As with other declaration attributes, we need to look through
> > TEMPLATE_DECL when looking up the abi_tag attribute.
> > 
> > PR c++/109715
> > 
> > gcc/cp/ChangeLog:
> > 
> > * mangle.cc (get_abi_tags): Look through TEMPLATE_DECL.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/abi/abi-tag25.C: New test.
> > * g++.dg/abi/abi-tag25a.C: New test.
> > ---
> >   gcc/cp/mangle.cc  |  6 ++
> >   gcc/testsuite/g++.dg/abi/abi-tag25.C  | 17 +
> >   gcc/testsuite/g++.dg/abi/abi-tag25a.C | 11 +++
> >   3 files changed, 34 insertions(+)
> >   create mode 100644 gcc/testsuite/g++.dg/abi/abi-tag25.C
> >   create mode 100644 gcc/testsuite/g++.dg/abi/abi-tag25a.C
> > 
> > diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
> > index 0684f0e6038..e3383df1836 100644
> > --- a/gcc/cp/mangle.cc
> > +++ b/gcc/cp/mangle.cc
> > @@ -530,6 +530,12 @@ get_abi_tags (tree t)
> > if (DECL_P (t) && DECL_DECLARES_TYPE_P (t))
> >   t = TREE_TYPE (t);
> >   +  if (TREE_CODE (t) == TEMPLATE_DECL
> > +  && DECL_TEMPLATE_RESULT (t)
> > +  /* We used to ignore abi_tag on function and variable templates.  */
> > +  && abi_check (19))
> > +t = DECL_TEMPLATE_RESULT (t);
> 
> Generally I try to call abi_check only when we know that there's something
> that will change the mangling, so here only if the template has ABI tags.  I
> suppose the only downside is a second mangling that produces the same name and
> gets ignored in mangle_decl so we don't need to be too strict about it, but it
> shouldn't be too hard to do that here?

D'oh, good point..  Otherwise IIUC we'd wastefully mangle most function
and variable templates (and perhaps their instantiations) twice when ABI
checks are enabled.

So like the following then?  Implemented using a recurse call but
we could easily implement it without recursion if anything.

-- >8 --

We need to look through TEMPLATE_DECL when looking up the abi_tag
attribute (as with other function and variable declaration attributes).

PR c++/109715

gcc/cp/ChangeLog:

* mangle.cc (get_abi_tags): Strip TEMPLATE_DECL before looking
up the abi_tag attribute.

gcc/testsuite/ChangeLog:

* g++.dg/abi/abi-tag25.C: New test.
* g++.dg/abi/abi-tag25a.C: New test.
---
 gcc/cp/mangle.cc  | 10 ++
 gcc/testsuite/g++.dg/abi/abi-tag25.C  | 17 +
 gcc/testsuite/g++.dg/abi/abi-tag25a.C | 11 +++
 3 files changed, 38 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/abi/abi-tag25.C
 create mode 100644 gcc/testsuite/g++.dg/abi/abi-tag25a.C

diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
index 0684f0e6038..365d470f46e 100644
--- a/gcc/cp/mangle.cc
+++ b/gcc/cp/mangle.cc
@@ -530,6 +530,16 @@ get_abi_tags (tree t)
   if (DECL_P (t) && DECL_DECLARES_TYPE_P (t))
 t = TREE_TYPE (t);
 
+  if (TREE_CODE (t) == TEMPLATE_DECL && DECL_TEMPLATE_RESULT (t))
+{
+  tree tags = get_abi_tags (DECL_TEMPLATE_RESULT (t));
+  /* We used to overlook abi_tag on function and variable templates.  */
+  if (tags && abi_check (19))
+   return tags;
+  else
+   return NULL_TREE;
+}
+
   tree attrs;
   if (TYPE_P (t))
 attrs = TYPE_ATTRIBUTES (t);
diff --git a/gcc/testsuite/g++.dg/abi/abi-tag25.C 
b/gcc/testsuite/g++.dg/abi/abi-tag25.C
new file mode 100644
index 000..9847f0dccc8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/abi-tag25.C
@@ -0,0 +1,17 @@
+// PR c++/109715
+// { dg-do compile { target c++11 } }
+
+template
+[[gnu::abi_tag("foo")]] void fun() { }
+
+template void fun();
+
+#if __cpp_variable_templates
+template
+[[gnu::abi_tag("foo")]] int var = 0;
+
+template int var;
+#endif
+
+// { dg-final { scan-assembler "_Z3funB3fooIiEvv" } }
+// { dg-final { scan-assembler "_Z3varB3fooIiE" { target c++14 } } }
diff --git a/gcc/testsuite/g++.dg/abi/abi-tag25a.C 
b/gcc/testsuite/g++.dg/abi/abi-tag25a.C
new file mode 100644
index 000..9499b5614cd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/a

Re: [PATCH] c++: abi_tag attribute on templates [PR109715]

2023-12-14 Thread Patrick Palka
On Thu, 14 Dec 2023, Jason Merrill wrote:

> On 12/14/23 14:17, Patrick Palka wrote:
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > trunk?  Do we want to condition this on abi_check (19)?
> 
> I think we do, sadly.

Sounds good, like so?  Bootstrap and regtest in progress.

-- >8 --

Subject: [PATCH] c++: abi_tag attribute on templates [PR109715]

As with other declaration attributes, we need to look through
TEMPLATE_DECL when looking up the abi_tag attribute.

PR c++/109715

gcc/cp/ChangeLog:

* mangle.cc (get_abi_tags): Look through TEMPLATE_DECL.

gcc/testsuite/ChangeLog:

* g++.dg/abi/abi-tag25.C: New test.
* g++.dg/abi/abi-tag25a.C: New test.
---
 gcc/cp/mangle.cc  |  6 ++
 gcc/testsuite/g++.dg/abi/abi-tag25.C  | 17 +
 gcc/testsuite/g++.dg/abi/abi-tag25a.C | 11 +++
 3 files changed, 34 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/abi/abi-tag25.C
 create mode 100644 gcc/testsuite/g++.dg/abi/abi-tag25a.C

diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
index 0684f0e6038..e3383df1836 100644
--- a/gcc/cp/mangle.cc
+++ b/gcc/cp/mangle.cc
@@ -530,6 +530,12 @@ get_abi_tags (tree t)
   if (DECL_P (t) && DECL_DECLARES_TYPE_P (t))
 t = TREE_TYPE (t);
 
+  if (TREE_CODE (t) == TEMPLATE_DECL
+  && DECL_TEMPLATE_RESULT (t)
+  /* We used to ignore abi_tag on function and variable templates.  */
+  && abi_check (19))
+t = DECL_TEMPLATE_RESULT (t);
+
   tree attrs;
   if (TYPE_P (t))
 attrs = TYPE_ATTRIBUTES (t);
diff --git a/gcc/testsuite/g++.dg/abi/abi-tag25.C 
b/gcc/testsuite/g++.dg/abi/abi-tag25.C
new file mode 100644
index 000..9847f0dccc8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/abi-tag25.C
@@ -0,0 +1,17 @@
+// PR c++/109715
+// { dg-do compile { target c++11 } }
+
+template
+[[gnu::abi_tag("foo")]] void fun() { }
+
+template void fun();
+
+#if __cpp_variable_templates
+template
+[[gnu::abi_tag("foo")]] int var = 0;
+
+template int var;
+#endif
+
+// { dg-final { scan-assembler "_Z3funB3fooIiEvv" } }
+// { dg-final { scan-assembler "_Z3varB3fooIiE" { target c++14 } } }
diff --git a/gcc/testsuite/g++.dg/abi/abi-tag25a.C 
b/gcc/testsuite/g++.dg/abi/abi-tag25a.C
new file mode 100644
index 000..9499b5614cd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/abi-tag25a.C
@@ -0,0 +1,11 @@
+// PR c++/109715
+// { dg-do compile { target c++11 } }
+// { dg-additional-options "-fabi-version=18 -fabi-compat-version=18 -Wabi=0" }
+
+#include "abi-tag25.C"
+
+// { dg-warning "mangled name" "" { target *-*-* } 5 }
+// { dg-warning "mangled name" "" { target *-*-* } 11 }
+
+// { dg-final { scan-assembler "_Z3funIiEvv" } }
+// { dg-final { scan-assembler "_Z3varIiE" { target c++14 } } }
-- 
2.43.0.76.g1a87c842ec




[PATCH] c++: section attribute on templates [PR70435, PR88061]

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

-- >8 --

The section attribute currently has no effect on templates because the
call to set_decl_section_name only happens at parse time and not also at
instantiation time.  This patch fixes this by propagating the section
name from the template to the instantiation.

PR c++/70435
PR c++/88061

gcc/cp/ChangeLog:

* pt.cc (tsubst_function_decl): Call set_decl_section_name.
(tsubst_decl) : Likewise.

gcc/testsuite/ChangeLog:

* g++.dg/ext/attr-section1.C: New test.
* g++.dg/ext/attr-section1a.C: New test.
* g++.dg/ext/attr-section2.C: New test.
* g++.dg/ext/attr-section2a.C: New test.
---
 gcc/cp/pt.cc  |  4 
 gcc/testsuite/g++.dg/ext/attr-section1.C  |  9 +
 gcc/testsuite/g++.dg/ext/attr-section1a.C | 11 +++
 gcc/testsuite/g++.dg/ext/attr-section2.C  |  9 +
 gcc/testsuite/g++.dg/ext/attr-section2a.C | 14 ++
 5 files changed, 47 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/attr-section1.C
 create mode 100644 gcc/testsuite/g++.dg/ext/attr-section1a.C
 create mode 100644 gcc/testsuite/g++.dg/ext/attr-section2.C
 create mode 100644 gcc/testsuite/g++.dg/ext/attr-section2a.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 50e6f062c85..8c4174fb902 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -14607,6 +14607,8 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t 
complain,
= remove_attribute ("visibility", DECL_ATTRIBUTES (r));
 }
   determine_visibility (r);
+  if (DECL_SECTION_NAME (t))
+set_decl_section_name (r, t);
   if (DECL_DEFAULTED_OUTSIDE_CLASS_P (r)
   && !processing_template_decl)
 defaulted_late_check (r);
@@ -15423,6 +15425,8 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain,
  = remove_attribute ("visibility", DECL_ATTRIBUTES (r));
  }
determine_visibility (r);
+   if (!local_p && DECL_SECTION_NAME (t))
+ set_decl_section_name (r, t);
  }
 
if (!local_p)
diff --git a/gcc/testsuite/g++.dg/ext/attr-section1.C 
b/gcc/testsuite/g++.dg/ext/attr-section1.C
new file mode 100644
index 000..b8ac65baa93
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/attr-section1.C
@@ -0,0 +1,9 @@
+// PR c++/70435
+// { dg-do compile { target { c++11 && named_sections } } }
+
+template
+[[gnu::section(".foo")]] void fun() { }
+
+template void fun();
+
+// { dg-final { scan-assembler {.section[ \t]+.foo} } }
diff --git a/gcc/testsuite/g++.dg/ext/attr-section1a.C 
b/gcc/testsuite/g++.dg/ext/attr-section1a.C
new file mode 100644
index 000..be24be2fc95
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/attr-section1a.C
@@ -0,0 +1,11 @@
+// PR c++/70435
+// { dg-do compile { target { c++11 && named_sections } } }
+
+template
+struct A {
+  [[gnu::section(".foo")]] void fun() { }
+};
+
+template struct A;
+
+// { dg-final { scan-assembler {.section[ \t]+.foo} } }
diff --git a/gcc/testsuite/g++.dg/ext/attr-section2.C 
b/gcc/testsuite/g++.dg/ext/attr-section2.C
new file mode 100644
index 000..a76f43b346f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/attr-section2.C
@@ -0,0 +1,9 @@
+// PR c++/88061
+// { dg-do compile { target { c++14 && named_sections } } }
+
+template
+[[gnu::section(".foo")]] int var = 42;
+
+template int var;
+
+// { dg-final { scan-assembler {.section[ \t]+.foo} } }
diff --git a/gcc/testsuite/g++.dg/ext/attr-section2a.C 
b/gcc/testsuite/g++.dg/ext/attr-section2a.C
new file mode 100644
index 000..a0b01cd8d93
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/attr-section2a.C
@@ -0,0 +1,14 @@
+// PR c++/88061
+// { dg-do compile { target { c++11 && named_sections } } }
+
+template
+struct A {
+  [[gnu::section(".foo")]] static int var;
+};
+
+template
+int A::var = 42;
+
+template struct A;
+
+// { dg-final { scan-assembler {.section[ \t]+.foo} } }
-- 
2.43.0.76.g1a87c842ec



[PATCH] c++: abi_tag attribute on templates [PR109715]

2023-12-14 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?  Do we want to condition this on abi_check (19)?

-- >8 --

As with other declaration attributes, we need to look through
TEMPLATE_DECL when looking up the abi_tag attribute.

PR c++/109715

gcc/cp/ChangeLog:

* mangle.cc (get_abi_tags): Look through TEMPLATE_DECL.

gcc/testsuite/ChangeLog:

* g++.dg/abi/abi-tag25.C: New test.
---
 gcc/cp/mangle.cc |  3 +++
 gcc/testsuite/g++.dg/abi/abi-tag25.C | 17 +
 2 files changed, 20 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/abi/abi-tag25.C

diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
index 0684f0e6038..1fbd879c116 100644
--- a/gcc/cp/mangle.cc
+++ b/gcc/cp/mangle.cc
@@ -527,6 +527,9 @@ get_abi_tags (tree t)
   if (!t || TREE_CODE (t) == NAMESPACE_DECL)
 return NULL_TREE;
 
+  if (TREE_CODE (t) == TEMPLATE_DECL && DECL_TEMPLATE_RESULT (t))
+t = DECL_TEMPLATE_RESULT (t);
+
   if (DECL_P (t) && DECL_DECLARES_TYPE_P (t))
 t = TREE_TYPE (t);
 
diff --git a/gcc/testsuite/g++.dg/abi/abi-tag25.C 
b/gcc/testsuite/g++.dg/abi/abi-tag25.C
new file mode 100644
index 000..9847f0dccc8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/abi-tag25.C
@@ -0,0 +1,17 @@
+// PR c++/109715
+// { dg-do compile { target c++11 } }
+
+template
+[[gnu::abi_tag("foo")]] void fun() { }
+
+template void fun();
+
+#if __cpp_variable_templates
+template
+[[gnu::abi_tag("foo")]] int var = 0;
+
+template int var;
+#endif
+
+// { dg-final { scan-assembler "_Z3funB3fooIiEvv" } }
+// { dg-final { scan-assembler "_Z3varB3fooIiE" { target c++14 } } }
-- 
2.43.0.76.g1a87c842ec



Re: [pushed 1/4] c++: copy location to AGGR_INIT_EXPR

2023-12-13 Thread Patrick Palka
On Wed, 13 Dec 2023, Jason Merrill wrote:

> Tested x86_64-pc-linux-gnu, applying to trunk.
> 
> -- 8< --
> 
> When building an AGGR_INIT_EXPR from a CALL_EXPR, we shouldn't lose location
> information.
> 
> gcc/cp/ChangeLog:
> 
>   * tree.cc (build_aggr_init_expr): Copy EXPR_LOCATION.

I made a similar change in the past which caused the debug regression
PR96997 which I fixed by reverting the change in r11-7263-g78a6d0e30d7950
(didn't do much deeper analysis than that).  Unfortunately it seems this
regression is back now.

> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp1y/constexpr-nsdmi7b.C: Adjust line.
>   * g++.dg/template/copy1.C: Likewise.
> ---
>  gcc/cp/tree.cc | 1 +
>  gcc/testsuite/g++.dg/cpp1y/constexpr-nsdmi7b.C | 4 ++--
>  gcc/testsuite/g++.dg/template/copy1.C  | 2 +-
>  3 files changed, 4 insertions(+), 3 deletions(-)
> 
> diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
> index da4d5c51f07..c4e41fd7b5c 100644
> --- a/gcc/cp/tree.cc
> +++ b/gcc/cp/tree.cc
> @@ -689,6 +689,7 @@ build_aggr_init_expr (tree type, tree init)
>CALL_EXPR_OPERATOR_SYNTAX (rval) = CALL_EXPR_OPERATOR_SYNTAX (init);
>CALL_EXPR_ORDERED_ARGS (rval) = CALL_EXPR_ORDERED_ARGS (init);
>CALL_EXPR_REVERSE_ARGS (rval) = CALL_EXPR_REVERSE_ARGS (init);
> +  SET_EXPR_LOCATION (rval, EXPR_LOCATION (init));
>  }
>else
>  rval = init;
> diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-nsdmi7b.C 
> b/gcc/testsuite/g++.dg/cpp1y/constexpr-nsdmi7b.C
> index a410e482664..586ee54124c 100644
> --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-nsdmi7b.C
> +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-nsdmi7b.C
> @@ -20,8 +20,8 @@ bar()
>  {
>A a = foo();
>a.p->n = 5;
> -  return a;
> -} // { dg-error "non-.constexpr." "" { target c++20_down } }
> +  return a; // { dg-error "non-.constexpr." "" { target c++20_down } }
> +}
>  
>  constexpr int
>  baz()
> diff --git a/gcc/testsuite/g++.dg/template/copy1.C 
> b/gcc/testsuite/g++.dg/template/copy1.C
> index eacd9e2c025..7e0a3805a77 100644
> --- a/gcc/testsuite/g++.dg/template/copy1.C
> +++ b/gcc/testsuite/g++.dg/template/copy1.C
> @@ -6,10 +6,10 @@
>  
>  struct A
>  {
> -  // { dg-error "reference" "" { target c++14_down } .+1 }
>A(A&); // { dg-message "A::A" "" { target c++14_down } 
> }
>template  A(T);   // { dg-message "A::A" "" { target c++14_down } 
> }
>  };
>  
> +// { dg-error "reference" "" { target c++14_down } .+1 }
>  A a = 0; // { dg-error "no match" "" { target c++14_down } }
>  
> 
> base-commit: d2b269ce30d77dbfc6c28c75887c330d4698b132
> -- 
> 2.39.3
> 
> 



Re: [PATCH] c++: unifying constants vs their type [PR99186, PR104867]

2023-12-12 Thread Patrick Palka
On Tue, 12 Dec 2023, Patrick Palka wrote:

> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
> for trunk?
> 
> -- >8 --
> 
> When unifying constants we need to generally treat constants of
> different types but same value as different, in light of auto template
> parameters.  This patch fixes this in a minimal way; it seems we could
> get away with just using template_args_equal here, as we do in the

or just cp_tree_equal for that matters because ...

> default case, but that's a simplification we could look into during next
> stage 1.
> 
>   PR c++/99186
>   PR c++/104867
> 
> gcc/cp/ChangeLog:
> 
>   * pt.cc (unify) : Compare types as well.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp1z/nontype-auto23.C: New test.
>   * g++.dg/cpp1z/nontype-auto24.C: New test.
> ---
>  gcc/cp/pt.cc|  2 ++
>  gcc/testsuite/g++.dg/cpp1z/nontype-auto23.C | 23 +
>  gcc/testsuite/g++.dg/cpp1z/nontype-auto24.C | 18 
>  3 files changed, 43 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/cpp1z/nontype-auto23.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp1z/nontype-auto24.C
> 
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index a8966e223f1..602dd02d29d 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -24709,6 +24709,8 @@ unify (tree tparms, tree targs, tree parm, tree arg, 
> int strict,
>/* Type INTEGER_CST can come from ordinary constant template args.  */
>  case INTEGER_CST:
>  case REAL_CST:
> +  if (!same_type_p (TREE_TYPE (parm), TREE_TYPE (arg)))
> + return unify_template_argument_mismatch (explain_p, parm, arg);
>while (CONVERT_EXPR_P (arg))
>   arg = TREE_OPERAND (arg, 0);

... this while loop seems to be dead code.

>  
> diff --git a/gcc/testsuite/g++.dg/cpp1z/nontype-auto23.C 
> b/gcc/testsuite/g++.dg/cpp1z/nontype-auto23.C
> new file mode 100644
> index 000..467559ffdda
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp1z/nontype-auto23.C
> @@ -0,0 +1,23 @@
> +// PR c++/99186
> +// { dg-do compile { target c++17 } }
> +
> +template
> +struct tuple_impl : tuple_impl { };
> +
> +template
> +struct tuple_impl { };
> +
> +template
> +struct tuple : tuple_impl<0, T, U> { };
> +
> +template
> +void get(const tuple_impl&);
> +
> +template
> +struct S;
> +
> +int main() {
> +   tuple,S<1U>> x;
> +   get>(x);
> +   get>(x);
> +}
> diff --git a/gcc/testsuite/g++.dg/cpp1z/nontype-auto24.C 
> b/gcc/testsuite/g++.dg/cpp1z/nontype-auto24.C
> new file mode 100644
> index 000..52e4c134ccd
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp1z/nontype-auto24.C
> @@ -0,0 +1,18 @@
> +// PR c++/104867
> +// { dg-do compile { target c++17 } }
> +
> +enum class Foo { A1 };
> +
> +enum class Bar { B1 };
> +
> +template struct enum_;
> +
> +template struct list { };
> +
> +template void f(list, V>);
> +
> +struct enum_type_map : list, int>, list, 
> double> { };
> +
> +int main() {
> +  f(enum_type_map());
> +}
> -- 
> 2.43.0.76.g1a87c842ec
> 
> 



[PATCH] c++: unifying constants vs their type [PR99186, PR104867]

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

-- >8 --

When unifying constants we need to generally treat constants of
different types but same value as different, in light of auto template
parameters.  This patch fixes this in a minimal way; it seems we could
get away with just using template_args_equal here, as we do in the
default case, but that's a simplification we could look into during next
stage 1.

PR c++/99186
PR c++/104867

gcc/cp/ChangeLog:

* pt.cc (unify) : Compare types as well.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/nontype-auto23.C: New test.
* g++.dg/cpp1z/nontype-auto24.C: New test.
---
 gcc/cp/pt.cc|  2 ++
 gcc/testsuite/g++.dg/cpp1z/nontype-auto23.C | 23 +
 gcc/testsuite/g++.dg/cpp1z/nontype-auto24.C | 18 
 3 files changed, 43 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/cpp1z/nontype-auto23.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1z/nontype-auto24.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index a8966e223f1..602dd02d29d 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -24709,6 +24709,8 @@ unify (tree tparms, tree targs, tree parm, tree arg, 
int strict,
   /* Type INTEGER_CST can come from ordinary constant template args.  */
 case INTEGER_CST:
 case REAL_CST:
+  if (!same_type_p (TREE_TYPE (parm), TREE_TYPE (arg)))
+   return unify_template_argument_mismatch (explain_p, parm, arg);
   while (CONVERT_EXPR_P (arg))
arg = TREE_OPERAND (arg, 0);
 
diff --git a/gcc/testsuite/g++.dg/cpp1z/nontype-auto23.C 
b/gcc/testsuite/g++.dg/cpp1z/nontype-auto23.C
new file mode 100644
index 000..467559ffdda
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/nontype-auto23.C
@@ -0,0 +1,23 @@
+// PR c++/99186
+// { dg-do compile { target c++17 } }
+
+template
+struct tuple_impl : tuple_impl { };
+
+template
+struct tuple_impl { };
+
+template
+struct tuple : tuple_impl<0, T, U> { };
+
+template
+void get(const tuple_impl&);
+
+template
+struct S;
+
+int main() {
+   tuple,S<1U>> x;
+   get>(x);
+   get>(x);
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/nontype-auto24.C 
b/gcc/testsuite/g++.dg/cpp1z/nontype-auto24.C
new file mode 100644
index 000..52e4c134ccd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/nontype-auto24.C
@@ -0,0 +1,18 @@
+// PR c++/104867
+// { dg-do compile { target c++17 } }
+
+enum class Foo { A1 };
+
+enum class Bar { B1 };
+
+template struct enum_;
+
+template struct list { };
+
+template void f(list, V>);
+
+struct enum_type_map : list, int>, list, double> 
{ };
+
+int main() {
+  f(enum_type_map());
+}
-- 
2.43.0.76.g1a87c842ec



[PATCH] c++: unifying FUNCTION_DECLs [PR93740]

2023-12-12 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
OK for trunk?  I considered removing the is_overloaded_fn test now as
well, but it could in theory be hit (and not subsumed by the
type_unknown_p test) for e.g. OVERLOAD of a single FUNCTION_DECL.  I
wonder if that's something we'd see here?  If not, I can remove the
test.  It seems safe to remove as far as the testsuite is concerned.

-- >8 --

unify currently always returns success when unifying two FUNCTION_DECLs
(due to the is_overloaded_fn deferment within the default case), which
means for the below testcase unify incorrectly matches ::foo with
::bar, which leads to deduction failure for the index_of calls due to
a bogus base class ambiguity.

This patch makes us instead handle unification of FUNCTION_DECL like
other decls, i.e. according to their identity.

PR c++/93740

gcc/cp/ChangeLog:

* pt.cc (unify) : Handle it like FIELD_DECL
and TEMPLATE_DECL.

gcc/testsuite/ChangeLog:

* g++.dg/template/ptrmem34.C: New test.
---
 gcc/cp/pt.cc |  1 +
 gcc/testsuite/g++.dg/template/ptrmem34.C | 27 
 2 files changed, 28 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/template/ptrmem34.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index c2ddbff405b..a8966e223f1 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -24967,6 +24967,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, 
int strict,
   gcc_unreachable ();
 
 case FIELD_DECL:
+case FUNCTION_DECL:
 case TEMPLATE_DECL:
   /* Matched cases are handled by the ARG == PARM test above.  */
   return unify_template_argument_mismatch (explain_p, parm, arg);
diff --git a/gcc/testsuite/g++.dg/template/ptrmem34.C 
b/gcc/testsuite/g++.dg/template/ptrmem34.C
new file mode 100644
index 000..c349ca55639
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/ptrmem34.C
@@ -0,0 +1,27 @@
+// PR c++/93740
+// { dg-do compile { target c++11 } }
+
+struct A {
+  void foo();
+  void bar();
+};
+
+template 
+struct const_val{};
+
+template 
+struct indexed_elem{};
+
+using mem_fun_A_foo = const_val;
+using mem_fun_A_bar = const_val;
+
+struct A_indexed_member_funcs
+  : indexed_elem<0, mem_fun_A_foo>,
+indexed_elem<1, mem_fun_A_bar>
+{};
+
+template 
+constexpr int index_of(indexed_elem) { return N; }
+
+static_assert(index_of(A_indexed_member_funcs{}) == 0, "");
+static_assert(index_of(A_indexed_member_funcs{}) == 1, "");
-- 
2.43.0.76.g1a87c842ec



[pushed] c++: add fixed testcase [PR63378]

2023-12-11 Thread Patrick Palka
We accept this testcase since r12-4453-g79802c5dcc043a.

PR c++/63378

gcc/testsuite/ChangeLog:

* g++.dg/template/fnspec3.C: New test.
---
 gcc/testsuite/g++.dg/template/fnspec3.C | 20 
 1 file changed, 20 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/template/fnspec3.C

diff --git a/gcc/testsuite/g++.dg/template/fnspec3.C 
b/gcc/testsuite/g++.dg/template/fnspec3.C
new file mode 100644
index 000..c36cb17751d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/fnspec3.C
@@ -0,0 +1,20 @@
+// PR c++/63378
+// { dg-do compile { target c++11 } }
+
+template
+struct B { };
+
+template
+struct A {
+private:
+  template
+  static B g();
+
+public:
+  template
+  auto f() -> decltype(g());
+};
+
+template<>
+template<>
+auto A::f() -> B;
-- 
2.43.0.76.g1a87c842ec



Re: [PATCH] c++: decltype of (non-captured variable) [PR83167]

2023-12-01 Thread Patrick Palka
On Fri, 1 Dec 2023, Jason Merrill wrote:

> On 12/1/23 12:32, Patrick Palka wrote:
> > On Tue, 14 Nov 2023, Jason Merrill wrote:
> > 
> > > On 11/14/23 11:10, Patrick Palka wrote:
> > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > > > trunk?
> > > > 
> > > > -- >8 --
> > > > 
> > > > For decltype((x)) within a lambda where x is not captured, we dubiously
> > > > require that the lambda has a capture default, unlike for decltype(x).
> > > > This patch fixes this inconsistency; I couldn't find a justification for
> > > > it in the standard.
> > > 
> > > The relevant passage seems to be
> > > 
> > > https://eel.is/c++draft/expr.prim#id.unqual-3
> > > 
> > > "If naming the entity from outside of an unevaluated operand within S
> > > would
> > > refer to an entity captured by copy in some intervening lambda-expression,
> > > then let E be the innermost such lambda-expression.
> > > 
> > > If there is such a lambda-expression and if P is in E's function parameter
> > > scope but not its parameter-declaration-clause, then the type of the
> > > expression is the type of a class member access expression ([expr.ref])
> > > naming
> > > the non-static data member that would be declared for such a capture in
> > > the
> > > object parameter ([dcl.fct]) of the function call operator of E."
> > > 
> > > In this case I guess there is no such lambda-expression because naming x
> > > won't
> > > refer to a capture by copy if the lambda doesn't capture anything, so we
> > > ignore the lambda.
> > > 
> > > Maybe refer to that in a comment?  OK with that change.
> > > 
> > > I'm surprised that it refers specifically to capture by copy, but I guess
> > > a
> > > capture by reference should have the same decltype as the captured
> > > variable?
> > 
> > Ah, seems like it.  So maybe we should get rid of the redundant
> > by-reference capture-default handling, to more closely mirror the
> > standard?
> > 
> > Also now that r14-6026-g73e2bdbf9bed48 made capture_decltype return
> > NULL_TREE to mean the capture is dependent, it seems we should just
> > inline capture_decltype into finish_decltype_type rather than
> > introducing another special return value to mean "fall back to ordinary
> > handling".
> > 
> > How does the following look?  Bootstrapped and regtested on
> > x86_64-pc-linux-gnu.
> > 
> > -- >8 --
> > 
> > PR c++/83167
> > 
> > gcc/cp/ChangeLog:
> > 
> > * semantics.cc (capture_decltype): Inline into its only caller ...
> > (finish_decltype_type): ... here.  Update nearby comment to refer
> > to recent standard.  Restrict uncaptured variable handling to just
> > lambdas with a by-copy capture-default.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/cpp0x/lambda/lambda-decltype4.C: New test.
> > ---
> >   gcc/cp/semantics.cc   | 107 +++---
> >   .../g++.dg/cpp0x/lambda/lambda-decltype4.C|  15 +++
> >   2 files changed, 55 insertions(+), 67 deletions(-)
> >   create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-decltype4.C
> > 
> > diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> > index fbbc18336a0..fb4c3992e34 100644
> > --- a/gcc/cp/semantics.cc
> > +++ b/gcc/cp/semantics.cc
> > @@ -53,7 +53,6 @@ along with GCC; see the file COPYING3.  If not see
> > static tree maybe_convert_cond (tree);
> >   static tree finalize_nrv_r (tree *, int *, void *);
> > -static tree capture_decltype (tree);
> > /* Used for OpenMP non-static data member privatization.  */
> >   @@ -11856,21 +11855,48 @@ finish_decltype_type (tree expr, bool
> > id_expression_or_member_access_p,
> >   }
> > else
> >   {
> > -  /* Within a lambda-expression:
> > -
> > -Every occurrence of decltype((x)) where x is a possibly
> > -parenthesized id-expression that names an entity of
> > -automatic storage duration is treated as if x were
> > -transformed into an access to a corresponding data member
> > -of the closure type that would have been declared if x
> > -were a use of the denoted entity.  */
> > if (outer_automatic_var_p (STRIP_REFERENCE_REF (expr))
> >   && current_function_decl
> >

Re: [pushed] c++: remove LAMBDA_EXPR_MUTABLE_P

2023-12-01 Thread Patrick Palka
On Thu, 30 Nov 2023, Jason Merrill wrote:

> Tested x86_64-pc-linux-gnu, applying to trunk.
> 
> -- 8< --
> 
> In review of the deducing 'this' patch it came up that LAMBDA_EXPR_MUTABLE_P
> doesn't make sense for a lambda with an explicit object parameter.  And it
> was never necessary, so let's remove it.
> 
> gcc/cp/ChangeLog:
> 
>   * cp-tree.h (LAMBDA_EXPR_MUTABLE_P): Remove.
>   * cp-tree.def: Remove documentation.
>   * lambda.cc (build_lambda_expr): Remove reference.
>   * parser.cc (cp_parser_lambda_declarator_opt): Likewise.
>   * pt.cc (tsubst_lambda_expr): Likewise.
>   * ptree.cc (cxx_print_lambda_node): Likewise.
>   * semantics.cc (capture_decltype): Get the object quals
>   from the object instead.
> ---
>  gcc/cp/cp-tree.h| 5 -
>  gcc/cp/lambda.cc| 1 -
>  gcc/cp/parser.cc| 1 -
>  gcc/cp/pt.cc| 1 -
>  gcc/cp/ptree.cc | 2 --
>  gcc/cp/semantics.cc | 9 ++---
>  gcc/cp/cp-tree.def  | 3 +--
>  7 files changed, 7 insertions(+), 15 deletions(-)
> 
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 5614b71eed4..964af1ddd85 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -461,7 +461,6 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
>TYPENAME_IS_CLASS_P (in TYPENAME_TYPE)
>STMT_IS_FULL_EXPR_P (in _STMT)
>TARGET_EXPR_LIST_INIT_P (in TARGET_EXPR)
> -  LAMBDA_EXPR_MUTABLE_P (in LAMBDA_EXPR)
>DECL_FINAL_P (in FUNCTION_DECL)
>QUALIFIED_NAME_IS_TEMPLATE (in SCOPE_REF)
>CONSTRUCTOR_IS_DEPENDENT (in CONSTRUCTOR)
> @@ -1478,10 +1477,6 @@ enum cp_lambda_default_capture_mode_type {
>  #define LAMBDA_EXPR_CAPTURES_THIS_P(NODE) \
>LAMBDA_EXPR_THIS_CAPTURE(NODE)
>  
> -/* Predicate tracking whether the lambda was declared 'mutable'.  */
> -#define LAMBDA_EXPR_MUTABLE_P(NODE) \
> -  TREE_LANG_FLAG_1 (LAMBDA_EXPR_CHECK (NODE))
> -
>  /* True iff uses of a const variable capture were optimized away.  */
>  #define LAMBDA_EXPR_CAPTURE_OPTIMIZED(NODE) \
>TREE_LANG_FLAG_2 (LAMBDA_EXPR_CHECK (NODE))
> diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc
> index 34d0190a89b..be8d240944d 100644
> --- a/gcc/cp/lambda.cc
> +++ b/gcc/cp/lambda.cc
> @@ -44,7 +44,6 @@ build_lambda_expr (void)
>LAMBDA_EXPR_THIS_CAPTURE (lambda) = NULL_TREE;
>LAMBDA_EXPR_REGEN_INFO   (lambda) = NULL_TREE;
>LAMBDA_EXPR_PENDING_PROXIES  (lambda) = NULL;
> -  LAMBDA_EXPR_MUTABLE_P(lambda) = false;
>return lambda;
>  }
>  
> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> index 2464d1a0783..1826b6175f5 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -11770,7 +11770,6 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, 
> tree lambda_expr)
>  
>if (lambda_specs.storage_class == sc_mutable)
>  {
> -  LAMBDA_EXPR_MUTABLE_P (lambda_expr) = 1;
>quals = TYPE_UNQUALIFIED;
>  }
>else if (lambda_specs.storage_class == sc_static)
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index c18718b319d..00a808bf323 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -19341,7 +19341,6 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t 
> complain, tree in_decl)
>  = LAMBDA_EXPR_LOCATION (t);
>LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (r)
>  = LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (t);
> -  LAMBDA_EXPR_MUTABLE_P (r) = LAMBDA_EXPR_MUTABLE_P (t);
>if (tree ti = LAMBDA_EXPR_REGEN_INFO (t))
>  LAMBDA_EXPR_REGEN_INFO (r)
>= build_template_info (t, add_to_template_args (TI_ARGS (ti),
> diff --git a/gcc/cp/ptree.cc b/gcc/cp/ptree.cc
> index 32c5b5280dc..d1f58921fab 100644
> --- a/gcc/cp/ptree.cc
> +++ b/gcc/cp/ptree.cc
> @@ -265,8 +265,6 @@ cxx_print_identifier (FILE *file, tree node, int indent)
>  void
>  cxx_print_lambda_node (FILE *file, tree node, int indent)
>  {
> -  if (LAMBDA_EXPR_MUTABLE_P (node))
> -fprintf (file, " /mutable");
>fprintf (file, " default_capture_mode=[");
>switch (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (node))
>  {
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index 04b0540599a..36b57ac9524 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -12792,9 +12792,12 @@ capture_decltype (tree decl)
>  
>if (!TYPE_REF_P (type))
>  {
> -  if (!LAMBDA_EXPR_MUTABLE_P (lam))
> - type = cp_build_qualified_type (type, (cp_type_quals (type)
> -|TYPE_QUAL_CONST));
> +  int quals = cp_type_quals (type);
> +  tree obtype = TREE_TYPE (DECL_ARGUMENTS (current_function_decl));
> +  gcc_checking_assert (!WILDCARD_TYPE_P (non_reference (obtype)));
> +  if (INDIRECT_TYPE_P (obtype))
> + quals |= cp_type_quals (TREE_TYPE (obtype));

Shouldn't we propagate cv-quals of a by-value object parameter as well?

> +  type = cp_build_qualified_type (type, quals);
>type = build_reference_type (type);
>  }
>return type;
> diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
> index 

Re: [PATCH] c++: decltype of (non-captured variable) [PR83167]

2023-12-01 Thread Patrick Palka
On Tue, 14 Nov 2023, Jason Merrill wrote:

> On 11/14/23 11:10, Patrick Palka wrote:
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > trunk?
> > 
> > -- >8 --
> > 
> > For decltype((x)) within a lambda where x is not captured, we dubiously
> > require that the lambda has a capture default, unlike for decltype(x).
> > This patch fixes this inconsistency; I couldn't find a justification for
> > it in the standard.
> 
> The relevant passage seems to be
> 
> https://eel.is/c++draft/expr.prim#id.unqual-3
> 
> "If naming the entity from outside of an unevaluated operand within S would
> refer to an entity captured by copy in some intervening lambda-expression,
> then let E be the innermost such lambda-expression.
> 
> If there is such a lambda-expression and if P is in E's function parameter
> scope but not its parameter-declaration-clause, then the type of the
> expression is the type of a class member access expression ([expr.ref]) naming
> the non-static data member that would be declared for such a capture in the
> object parameter ([dcl.fct]) of the function call operator of E."
> 
> In this case I guess there is no such lambda-expression because naming x won't
> refer to a capture by copy if the lambda doesn't capture anything, so we
> ignore the lambda.
> 
> Maybe refer to that in a comment?  OK with that change.
> 
> I'm surprised that it refers specifically to capture by copy, but I guess a
> capture by reference should have the same decltype as the captured variable?

Ah, seems like it.  So maybe we should get rid of the redundant
by-reference capture-default handling, to more closely mirror the
standard?

Also now that r14-6026-g73e2bdbf9bed48 made capture_decltype return
NULL_TREE to mean the capture is dependent, it seems we should just
inline capture_decltype into finish_decltype_type rather than
introducing another special return value to mean "fall back to ordinary
handling".

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

-- >8 --

PR c++/83167

gcc/cp/ChangeLog:

* semantics.cc (capture_decltype): Inline into its only caller ...
(finish_decltype_type): ... here.  Update nearby comment to refer
to recent standard.  Restrict uncaptured variable handling to just
lambdas with a by-copy capture-default.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/lambda/lambda-decltype4.C: New test.
---
 gcc/cp/semantics.cc   | 107 +++---
 .../g++.dg/cpp0x/lambda/lambda-decltype4.C|  15 +++
 2 files changed, 55 insertions(+), 67 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-decltype4.C

diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index fbbc18336a0..fb4c3992e34 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -53,7 +53,6 @@ along with GCC; see the file COPYING3.  If not see
 
 static tree maybe_convert_cond (tree);
 static tree finalize_nrv_r (tree *, int *, void *);
-static tree capture_decltype (tree);
 
 /* Used for OpenMP non-static data member privatization.  */
 
@@ -11856,21 +11855,48 @@ finish_decltype_type (tree expr, bool 
id_expression_or_member_access_p,
 }
   else
 {
-  /* Within a lambda-expression:
-
-Every occurrence of decltype((x)) where x is a possibly
-parenthesized id-expression that names an entity of
-automatic storage duration is treated as if x were
-transformed into an access to a corresponding data member
-of the closure type that would have been declared if x
-were a use of the denoted entity.  */
   if (outer_automatic_var_p (STRIP_REFERENCE_REF (expr))
  && current_function_decl
  && LAMBDA_FUNCTION_P (current_function_decl))
{
- type = capture_decltype (STRIP_REFERENCE_REF (expr));
- if (!type)
-   goto dependent;
+ /* [expr.prim.id.unqual]/3: If naming the entity from outside of an
+unevaluated operand within S would refer to an entity captured by
+copy in some intervening lambda-expression, then let E be the
+innermost such lambda-expression.
+
+If there is such a lambda-expression and if P is in E's function
+parameter scope but not its parameter-declaration-clause, then the
+type of the expression is the type of a class member access
+expression naming the non-static data member that would be declared
+for such a capture in the object parameter of the function call
+operator of E."  */
+ tree decl = STRIP_REFERENCE_REF (expr);
+ tree lam = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT 
(current_function_decl));
+ tree cap = lookup_name (DECL_NAME (decl), LOOK

[PATCH] libstdc++: Simplify ranges::to closure objects

2023-11-30 Thread Patrick Palka
Tested on x86_64-pc-linux-gnu, does this look OK for trunk?

-- >8 --

Use the existing _Partial range adaptor closure object in the
definition of ranges::to instead of essentially open coding it.

libstdc++-v3/ChangeLog:

* include/std/ranges (__detail::_ToClosure): Replace with ...
(__detail::_To): ... this.
(__detail::_ToClosure2): Replace with ...
(__detail::To2): ... this.
(to): Simplify using the existing _Partial range adaptor
closure object.
---
 libstdc++-v3/include/std/ranges | 140 
 1 file changed, 32 insertions(+), 108 deletions(-)

diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 9d4c2e01c4d..33e576e563a 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -1007,6 +1007,7 @@ namespace views::__adaptor
 
   // Invoke _Adaptor with arguments __r, _M_args... according to the
   // value category of this _Partial object.
+  // TODO: use explicit object functions ("deducing this").
   template
requires __adaptor_invocable<_Adaptor, _Range, const _Args&...>
constexpr auto
@@ -1137,6 +1138,7 @@ namespace views::__adaptor
 
   // Invoke _M_rhs(_M_lhs(__r)) according to the value category of this
   // range adaptor closure object.
+  // TODO: use explicit object functions ("deducing this").
   template
requires __pipe_invocable
constexpr auto
@@ -9391,59 +9393,16 @@ namespace __detail
 /// @cond undocumented
 namespace __detail
 {
-  template
-class _ToClosure
-: public views::__adaptor::_RangeAdaptorClosure<_ToClosure<_Cont, 
_Args...>>
+  template
+struct _To
 {
-  tuple...> _M_bound_args;
-
-public:
-  constexpr
-  _ToClosure(_Args&&... __args)
-  : _M_bound_args(std::forward<_Args>(__args)...)
-  { }
-
-  // TODO: use explicit object functions ("deducing this").
-
-  template
-   constexpr auto
-   operator()(_Rg&& __r) &
-   {
- return std::apply([&__r](_Tp&&... __args) {
-   return ranges::to<_Cont>(std::forward<_Rg>(__r),
-std::forward<_Tp>(__args)...);
- }, _M_bound_args);
-   }
-
-  template
-   constexpr auto
-   operator()(_Rg&& __r) const &
-   {
- return std::apply([&__r](_Tp&&... __args) {
-   return ranges::to<_Cont>(std::forward<_Rg>(__r),
-std::forward<_Tp>(__args)...);
- }, _M_bound_args);
-   }
-
-  template
-   constexpr auto
-   operator()(_Rg&& __r) &&
-   {
- return std::apply([&__r](_Tp&&... __args) {
-   return ranges::to<_Cont>(std::forward<_Rg>(__r),
-std::forward<_Tp>(__args)...);
- }, std::move(_M_bound_args));
-   }
-
-  template
-   constexpr auto
-   operator()(_Rg&& __r) const &&
-   {
- return std::apply([&__r](_Tp&&... __args) {
-   return ranges::to<_Cont>(std::forward<_Rg>(__r),
-std::forward<_Tp>(__args)...);
- }, std::move(_M_bound_args));
-   }
+  template
+  constexpr auto
+  operator()(_Range&& __r, _Args&&... __args) const
+  {
+   return ranges::to<_Cont>(std::forward<_Range>(__r),
+std::forward<_Args>(__args)...);
+  }
 };
 } // namespace __detail
 /// @endcond
@@ -9465,66 +9424,27 @@ namespace __detail
*/
   template
 requires (!view<_Cont>)
-constexpr __detail::_ToClosure<_Cont, _Args...>
+constexpr auto
 to [[nodiscard]] (_Args&&... __args)
-{ return {std::forward<_Args>(__args)...}; }
+{
+  using __detail::_To;
+  using views::__adaptor::_Partial;
+  return _Partial<_To<_Cont>, 
decay_t<_Args>...>{std::forward<_Args>(__args)...};
+}
 
 /// @cond undocumented
 namespace __detail
 {
-  template typename _Cont, typename... _Args>
-class _ToClosure2
-: public views::__adaptor::_RangeAdaptorClosure<_ToClosure2<_Cont, 
_Args...>>
+  template typename _Cont>
+struct _To2
 {
-  tuple...> _M_bound_args;
-
-public:
-  constexpr
-  _ToClosure2(_Args&&... __args)
-  : _M_bound_args(std::forward<_Args>(__args)...)
-  { }
-
-  // TODO: use explicit object functions ("deducing this").
-
-  template
-   constexpr auto
-   operator()(_Rg&& __r) &
-   {
- return std::apply([&__r](_Tp&&... __args) {
-   return ranges::to<_Cont>(std::forward<_Rg>(__r),
-std::forward<_Tp>(__args)...);
- }, _M_bound_args);
-   }
-
-  template
-   constexpr auto
-   operator()(_Rg&& __r) const &
-   {
- return std::apply([&__r](_Tp&&... __args) {
-   return ranges::to<_Cont>(std::forward<_Rg>(__r),
-std::forward<_Tp>(__args)...);
- 

Re: [PATCH v3 3/3] c++: note other candidates when diagnosing deletedness

2023-11-30 Thread Patrick Palka
On Fri, 27 Oct 2023, Patrick Palka wrote:

> On Fri, 27 Oct 2023, Jason Merrill wrote:
> 
> > On 10/27/23 15:55, Patrick Palka wrote:
> > > With the previous two patches in place, we can now extend our
> > > deletedness diagnostic to note the other considered candidates, e.g.:
> > > 
> > >deleted16.C: In function 'int main()':
> > >deleted16.C:10:4: error: use of deleted function 'void f(int)'
> > >   10 |   f(0);
> > >  |   ~^~~
> > >deleted16.C:5:6: note: declared here
> > >5 | void f(int) = delete;
> > >  |  ^
> > >deleted16.C:5:6: note: candidate: 'void f(int)' (deleted)
> > >deleted16.C:6:6: note: candidate: 'void f(...)'
> > >6 | void f(...);
> > >  |  ^
> > >deleted16.C:7:6: note: candidate: 'void f(int, int)'
> > >7 | void f(int, int);
> > >  |  ^
> > >deleted16.C:7:6: note:   candidate expects 2 arguments, 1 provided
> > > 
> > > These notes are controlled by a new command line flag -fnote-all-cands,
> > > which also controls whether we note ignored candidates more generally.
> > > 
> > > gcc/ChangeLog:
> > > 
> > >   * doc/invoke.texi (C++ Dialect Options): Document -fnote-all-cands.
> > > 
> > > gcc/c-family/ChangeLog:
> > > 
> > >   * c.opt: Add -fnote-all-cands.
> > > 
> > > gcc/cp/ChangeLog:
> > > 
> > >   * call.cc (print_z_candidates): Only print ignored candidates
> > >   when -fnote-all-cands is set.
> > >   (build_over_call): When diagnosing deletedness, call
> > >   print_z_candidates if -fnote-all-cands is set.
> > 
> > My suggestion was also to suggest using the flag in cases where it would 
> > make
> > a difference, e.g.
> > 
> > note: some candidates omitted, use '-fnote-all-cands' to display them
> 
> Ah thanks, fixed.  That'll help a lot with discoverability of the flag.
> 
> > 
> > Maybe "-fdiagnostics-all-candidates"?
> 
> Nice, that's a better name indeed :)
> 
> How does the following look?  Full bootstrap/regtest in progress.
> 
> Here's the output of e.g. deleted16a.C.  I think I'd prefer to not print
> the source line when emitting the suggestion, but I don't know how to do
> that properly (aside from e.g. emitting the note at UNKNOWN_LOCATION).
> 
> In file included from gcc/testsuite/g++.dg/cpp0x/deleted16a.C:4:
> gcc/testsuite/g++.dg/cpp0x/deleted16.C: In function ‘int main()’:
> gcc/testsuite/g++.dg/cpp0x/deleted16.C:21:4: error: use of deleted function 
> ‘void f(int)’
>21 |   f(0); // { dg-error "deleted" }
>   |   ~^~~
> gcc/testsuite/g++.dg/cpp0x/deleted16.C:6:6: note: declared here
> 6 | void f(int) = delete; // { dg-message "declared here" }
>   |  ^
> gcc/testsuite/g++.dg/cpp0x/deleted16.C:21:4: note: use 
> ‘-fdiagnostics-all-candidates’ to display considered candidates
>21 |   f(0); // { dg-error "deleted" }
>   |   ~^~~
> gcc/testsuite/g++.dg/cpp0x/deleted16.C:22:4: error: use of deleted function 
> ‘void g(int)’
>22 |   g(0); // { dg-error "deleted" }
>   |   ~^~~
> gcc/testsuite/g++.dg/cpp0x/deleted16.C:12:6: note: declared here
>12 | void g(int) = delete; // { dg-message "declared here" }
>   |  ^
> gcc/testsuite/g++.dg/cpp0x/deleted16.C:22:4: note: use 
> ‘-fdiagnostics-all-candidates’ to display considered candidates
>22 |   g(0); // { dg-error "deleted" }
>   |   ~^~~
> gcc/testsuite/g++.dg/cpp0x/deleted16.C:23:4: error: use of deleted function 
> ‘void h(T, T) [with T = int]’
>23 |   h(1, 1); // { dg-error "deleted" }
>   |   ~^~
> gcc/testsuite/g++.dg/cpp0x/deleted16.C:17:24: note: declared here
>17 | template void h(T, T) = delete; // { dg-message "declared 
> here|candidate" }
>   |^
> gcc/testsuite/g++.dg/cpp0x/deleted16.C:23:4: note: use 
> ‘-fdiagnostics-all-candidates’ to display considered candidates
>23 |   h(1, 1); // { dg-error "deleted" }
>   |   ~^~
> 
> -- >8 --
> 
> 
> Subject: [PATCH 3/3] c++: note other candidates when diagnosing deletedness
> 
> With the previous two patches in place, we can now extend our
> deletedness diagnostic to note the other considered candidates, e.g.:
> 
>   deleted16.C: In function 'int main()':
>   deleted16.C:10:4: error: use of deleted function 'void f(int)'
>  10 |   f(0);
> |   ~^~~
>   deleted16.C:5:6: note: declared 

Re: [PATCH] c++: partial spec constraint checking context [PR105220]

2023-11-30 Thread Patrick Palka
On Fri, 3 Nov 2023, Patrick Palka wrote:

> On Tue, 3 May 2022, Jason Merrill wrote:
> 
> > On 5/2/22 14:50, Patrick Palka wrote:
> > > Currently when checking the constraints of a class template, we do so in
> > > the context of the template, not the specialized type.  This is the best
> > > we can do for a primary template since the specialized type is valid
> > > only if the primary template's constraints are satisfied.
> > 
> > Hmm, that's unfortunate.  It ought to be possible, if awkward, to form the
> > type long enough to check its constraints.
> 
> (Sorry, lost track of this patch...)
> 
> Seems doable, but I'm not sure if would make any difference in practice?
> 
> If the access context during satisfaction of a primary class template's
> constraints is the specialization rather than the primary template,
> then that should only make a difference if there's some friend declaration
> naming the specialization.  But that'd mean the specialization's
> constraints had to have been satisfied at that point, before the friend
> declaration went into effect.  So either the constraints don't depend on
> the access granted by the friend declaration anyway, or they do and the
> program is ill-formed (due to either satifaction failure or instability) IIUC.
> 
> For example, I don't think an adapted version of the testcase without a
> partial specialization is valid, regardless of whether the access context
> during satisfaction of A is A or just A:
> 
> template
> concept fooable = requires(T t) { t.foo(); };
> 
> template
> struct A { };
> 
> struct B {
> private:
>   friend struct A; // satisfaction failure at this point
>   void foo();
> };
> 
> template struct A;

... so in light of the above, I wonder if the original patch can go in
as-is?

> 
> 
> > 
> > > But for a
> > > partial specialization, we can assume the specialized type is valid (as
> > > a consequence of constraints being checked only when necessary), so we
> > > arguably should check the constraints on a partial specialization more
> > > specifically in the context of the specialized type, not the template.
> > > 
> > > This patch implements this by substituting and setting the access
> > > context appropriately in satisfy_declaration_constraints.  Note that
> > > setting the access context in this case is somewhat redundant since the
> > > relevant caller most_specialized_partial_spec will already have set the
> > > access context to the specialiation, but this redundancy should be 
> > > harmless.
> > > 
> > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > > trunk and perhaps 12.2 (after the branch is thawed)?
> > > 
> > >   PR c++/105220
> > > 
> > > gcc/cp/ChangeLog:
> > > 
> > >   * constraint.cc (satisfy_declaration_constraints): When checking
> > >   the constraints of a partial template specialization, do so in
> > >   the context of the specialized type not the template.
> > > 
> > > gcc/testsuite/ChangeLog:
> > > 
> > >   * g++.dg/cpp2a/concepts-partial-spec12.C: New test.
> > > ---
> > >   gcc/cp/constraint.cc  | 17 ++---
> > >   .../g++.dg/cpp2a/concepts-partial-spec12.C| 19 +++
> > >   2 files changed, 33 insertions(+), 3 deletions(-)
> > >   create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec12.C
> > > 
> > > diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> > > index 94f6222b436..772f8532b47 100644
> > > --- a/gcc/cp/constraint.cc
> > > +++ b/gcc/cp/constraint.cc
> > > @@ -3253,11 +3253,22 @@ satisfy_declaration_constraints (tree t, tree 
> > > args,
> > > sat_info info)
> > >   {
> > > if (!push_tinst_level (t, args))
> > >   return result;
> > > -  tree pattern = DECL_TEMPLATE_RESULT (t);
> > > +  tree ascope = DECL_TEMPLATE_RESULT (t);
> > > +  if (CLASS_TYPE_P (TREE_TYPE (t))
> > > +   && CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (t)))
> > > + {
> > > +   gcc_checking_assert (t == most_general_template (t));
> > > +   /* When checking the constraints on a partial specialization,
> > > +  do so in the context of the specialized type, not the template.
> > > +  This substitution should always succeed since we shouldn't
> > > +  be checking constraints thereof unless the speci

[PATCH] c++: bogus -Wparentheses warning [PR112765]

2023-11-29 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linu-xgnu, does this look OK for
trunk?

-- >8 --

We need to consistently look through implicit INDIRECT_REF when
setting/checking for -Wparentheses warning suppression.  In passing
use STRIP_REFERENCE_REF consistently as well.

PR c++/112765

gcc/cp/ChangeLog:

* pt.cc (tsubst_expr) : Look through
implicit INDIRECT_REF when propagating -Wparentheses
warning suppression.
* semantics.cc (maybe_warn_unparenthesized_assignment):
Replace REFERENCE_REF_P stripping with STRIP_REFERENCE_REF.
(finish_parenthesized_expr): Likewise.

gcc/testsuite/ChangeLog:

* g++.dg/warn/Wparentheses-33.C: New test.
---
 gcc/cp/pt.cc|  2 +-
 gcc/cp/semantics.cc |  6 ++
 gcc/testsuite/g++.dg/warn/Wparentheses-33.C | 24 +
 3 files changed, 27 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/warn/Wparentheses-33.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 00b095265b6..fc4464dec02 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -20282,7 +20282,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
   build_x_modify_expr sets it and it must not be reset
   here.  */
if (warning_suppressed_p (t, OPT_Wparentheses))
- suppress_warning (r, OPT_Wparentheses);
+ suppress_warning (STRIP_REFERENCE_REF (r), OPT_Wparentheses);
 
RETURN (r);
   }
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 3bf586453dc..fc00c20cba4 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -871,8 +871,7 @@ is_assignment_op_expr_p (tree t)
 void
 maybe_warn_unparenthesized_assignment (tree t, tsubst_flags_t complain)
 {
-  if (REFERENCE_REF_P (t))
-t = TREE_OPERAND (t, 0);
+  t = STRIP_REFERENCE_REF (t);
 
   if ((complain & tf_warning)
   && warn_parentheses
@@ -2176,8 +2175,7 @@ finish_parenthesized_expr (cp_expr expr)
 {
   /* This inhibits warnings in maybe_warn_unparenthesized_assignment
 and c_common_truthvalue_conversion.  */
-  tree inner = REFERENCE_REF_P (expr) ? TREE_OPERAND (expr, 0) : *expr;
-  suppress_warning (inner, OPT_Wparentheses);
+  suppress_warning (STRIP_REFERENCE_REF (*expr), OPT_Wparentheses);
 }
 
   if (TREE_CODE (expr) == OFFSET_REF
diff --git a/gcc/testsuite/g++.dg/warn/Wparentheses-33.C 
b/gcc/testsuite/g++.dg/warn/Wparentheses-33.C
new file mode 100644
index 000..6c65037d1b4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wparentheses-33.C
@@ -0,0 +1,24 @@
+// PR c++/112765
+
+struct A {
+  A& operator=(const A&);
+  operator bool() const;
+};
+
+template
+void f(A a1, A a2) {
+  if ((a2 = a1)) // { dg-bogus "suggest parentheses" }
+return;
+  bool b = (a2 = a1); // { dg-bogus "suggest parentheses" }
+}
+
+template void f(A, A);
+
+template
+void g(T a1, T a2) {
+  if ((a2 = a1)) // { dg-bogus "suggest parentheses" }
+return;
+  bool b = (a2 = a1); // { dg-bogus "suggest parentheses" }
+}
+
+template void g(A, A);
-- 
2.43.0.rc1



Re: [PATCH] c++: wrong ambiguity in accessing static field [PR112744]

2023-11-29 Thread Patrick Palka
On Wed, 29 Nov 2023, Marek Polacek wrote:

> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> 
> Now that I'm posting this patch, I think you'll probably want me to use
> ba_any unconditionally.  That works too; g++.dg/tc1/dr52.C just needs
> a trivial testsuite tweak:
>   'C' is not an accessible base of 'X'
> v.
>   'C' is an inaccessible base of 'X'
> We should probably unify those messages...
> 
> -- >8 --
> Given
> 
>   struct A { constexpr static int a = 0; };
>   struct B : A {};
>   struct C : A {};
>   struct D : B, C {};
> 
> we give the "'A' is an ambiguous base of 'D'" error for
> 
>   D{}.A::a;
> 
> which seems wrong: 'a' is a static data member so there is only one copy
> so it can be unambiguously referred to even if there are multiple A
> objects.  clang++/MSVC/icx agree.
> 
>   PR c++/112744
> 
> gcc/cp/ChangeLog:
> 
>   * typeck.cc (finish_class_member_access_expr): When accessing
>   a static data member, use ba_any for lookup_base.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/lookup/scoped11.C: New test.
>   * g++.dg/lookup/scoped12.C: New test.
>   * g++.dg/lookup/scoped13.C: New test.
> ---
>  gcc/cp/typeck.cc   | 21 ++---
>  gcc/testsuite/g++.dg/lookup/scoped11.C | 14 ++
>  gcc/testsuite/g++.dg/lookup/scoped12.C | 14 ++
>  gcc/testsuite/g++.dg/lookup/scoped13.C | 14 ++
>  4 files changed, 60 insertions(+), 3 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/lookup/scoped11.C
>  create mode 100644 gcc/testsuite/g++.dg/lookup/scoped12.C
>  create mode 100644 gcc/testsuite/g++.dg/lookup/scoped13.C
> 
> diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
> index e995fb6ddd7..c4de8bb2616 100644
> --- a/gcc/cp/typeck.cc
> +++ b/gcc/cp/typeck.cc
> @@ -3476,7 +3476,7 @@ finish_class_member_access_expr (cp_expr object, tree 
> name, bool template_p,
>  name, scope);
> return error_mark_node;
>   }
> -   
> +
> if (TREE_SIDE_EFFECTS (object))
>   val = build2 (COMPOUND_EXPR, TREE_TYPE (val), object, val);
> return val;
> @@ -3493,9 +3493,24 @@ finish_class_member_access_expr (cp_expr object, tree 
> name, bool template_p,
> return error_mark_node;
>   }
>  
> +   /* NAME may refer to a static data member, in which case there is
> +  one copy of the data member that is shared by all the objects of
> +  the class.  So NAME can be unambiguously referred to even if
> +  there are multiple indirect base classes containing NAME.  */
> +   const base_access ba = [scope, name] ()
> + {
> +   if (identifier_p (name))
> + {
> +   tree m = lookup_member (scope, name, /*protect=*/0,
> +   /*want_type=*/false, tf_none);
> +   if (!m || VAR_P (m))
> + return ba_any;

I wonder if we want to return ba_check_bit instead of ba_any so that we
still check access of the selected base?

  struct A { constexpr static int a = 0; };
  struct D : private A {};

  void f() {
D{}.A::a; // #1 GCC (and Clang) currently rejects
  }

  template
  void g() {
D{}.T::a; // #2 GCC currently rejects, Clang accepts?!
  }

  template void g();

> + }
> +   return ba_check;
> + } ();
> +
> /* Find the base of OBJECT_TYPE corresponding to SCOPE.  */
> -   access_path = lookup_base (object_type, scope, ba_check,
> -  NULL, complain);
> +   access_path = lookup_base (object_type, scope, ba, NULL, complain);
> if (access_path == error_mark_node)
>   return error_mark_node;
> if (!access_path)
> diff --git a/gcc/testsuite/g++.dg/lookup/scoped11.C 
> b/gcc/testsuite/g++.dg/lookup/scoped11.C
> new file mode 100644
> index 000..be743522fce
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/lookup/scoped11.C
> @@ -0,0 +1,14 @@
> +// PR c++/112744
> +// { dg-do compile }
> +
> +struct A { const static int a = 0; };
> +struct B : A {};
> +struct C : A {};
> +struct D : B, C {};
> +
> +int main()
> +{
> +  D d;
> +  (void) d.a;
> +  (void) d.A::a;
> +}
> diff --git a/gcc/testsuite/g++.dg/lookup/scoped12.C 
> b/gcc/testsuite/g++.dg/lookup/scoped12.C
> new file mode 100644
> index 000..ffa145598fd
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/lookup/scoped12.C
> @@ -0,0 +1,14 @@
> +// PR c++/112744
> +// { dg-do compile }
> +
> +class A { const static int a = 0; };
> +struct B : A {};
> +struct C : A {};
> +struct D : B, C {};
> +
> +int main()
> +{
> +  D d;
> +  (void) d.a;  // { dg-error "private" }
> +  (void) d.A::a;  // { dg-error "private" }
> +}
> diff --git a/gcc/testsuite/g++.dg/lookup/scoped13.C 
> b/gcc/testsuite/g++.dg/lookup/scoped13.C
> new file mode 100644
> index 000..970e1aa833e
> --- /dev/null
> +++ 

Re: [committed v2] libstdc++: Define std::ranges::to for C++23 (P1206R7) [PR111055]

2023-11-29 Thread Patrick Palka
On Thu, 23 Nov 2023, Jonathan Wakely wrote:

> Here's the finished version of the std::ranges::to patch, which I've
> pushed to trunk.
> 
> Tested x86_64-linux.
> 
> -- >8 --
> 
> This adds the std::ranges::to functions for C++23. The rest of P1206R7
> is not yet implemented, i.e. the new constructors taking the
> std::from_range tag, and the new insert_range, assign_range, etc. member
> functions. std::ranges::to works with the standard containers even
> without the new constructors, so this is useful immediately.
> 
> The __cpp_lib_ranges_to_container feature test macro can be defined now,
> because that only indicates support for the changes in , which
> are implemented by this patch. The __cpp_lib_containers_ranges macro
> will be defined once all containers support the new member functions.
> 
> libstdc++-v3/ChangeLog:
> 
>   PR libstdc++/111055
>   * include/bits/ranges_base.h (from_range_t): Define new tag
>   type.
>   (from_range): Define new tag object.
>   * include/bits/version.def (ranges_to_container): Define.
>   * include/bits/version.h: Regenerate.
>   * include/std/ranges (ranges::to): Define.
>   * testsuite/std/ranges/conv/1.cc: New test.
>   * testsuite/std/ranges/conv/2_neg.cc: New test.
>   * testsuite/std/ranges/conv/version.cc: New test.
> ---
>  libstdc++-v3/include/bits/ranges_base.h   |   8 +-
>  libstdc++-v3/include/bits/version.def |  34 +-
>  libstdc++-v3/include/bits/version.h   | 111 +++---
>  libstdc++-v3/include/std/ranges   | 361 -
>  libstdc++-v3/testsuite/std/ranges/conv/1.cc   | 369 ++
>  .../testsuite/std/ranges/conv/2_neg.cc|  24 ++
>  .../testsuite/std/ranges/conv/version.cc  |  19 +
>  7 files changed, 866 insertions(+), 60 deletions(-)
>  create mode 100644 libstdc++-v3/testsuite/std/ranges/conv/1.cc
>  create mode 100644 libstdc++-v3/testsuite/std/ranges/conv/2_neg.cc
>  create mode 100644 libstdc++-v3/testsuite/std/ranges/conv/version.cc
> 
> diff --git a/libstdc++-v3/include/bits/ranges_base.h 
> b/libstdc++-v3/include/bits/ranges_base.h
> index 7fa43d1965a..1ca2c5ce2bb 100644
> --- a/libstdc++-v3/include/bits/ranges_base.h
> +++ b/libstdc++-v3/include/bits/ranges_base.h
> @@ -37,6 +37,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  
>  #ifdef __cpp_lib_concepts
>  namespace std _GLIBCXX_VISIBILITY(default)
> @@ -1056,8 +1057,13 @@ namespace ranges
>  using borrowed_iterator_t = __conditional_t,
>   iterator_t<_Range>,
>   dangling>;
> -
>  } // namespace ranges
> +
> +#if __glibcxx_ranges_to_container // C++ >= 23
> +  struct from_range_t { explicit from_range_t() = default; };
> +  inline constexpr from_range_t from_range{};
> +#endif
> +
>  _GLIBCXX_END_NAMESPACE_VERSION
>  } // namespace std
>  #endif // library concepts
> diff --git a/libstdc++-v3/include/bits/version.def 
> b/libstdc++-v3/include/bits/version.def
> index 605708dfee7..140777832ed 100644
> --- a/libstdc++-v3/include/bits/version.def
> +++ b/libstdc++-v3/include/bits/version.def
> @@ -1439,19 +1439,21 @@ ftms = {
>};
>  };
>  
> -ftms = {
> -  name = to_underlying;
> -  values = {
> -v = 202102;
> -cxxmin = 23;
> -  };
> -};
> +//ftms = {
> +//  name = container_ranges;
> +//  values = {
> +//v = 202202;
> +//cxxmin = 23;
> +//hosted = yes;
> +//  };
> +//};
>  
>  ftms = {
> -  name = unreachable;
> +  name = ranges_to_container;
>values = {
>  v = 202202;
>  cxxmin = 23;
> +hosted = yes;
>};
>  };
>  
> @@ -1683,6 +1685,22 @@ ftms = {
>};
>  };
>  
> +ftms = {
> +  name = to_underlying;
> +  values = {
> +v = 202102;
> +cxxmin = 23;
> +  };
> +};
> +
> +ftms = {
> +  name = unreachable;
> +  values = {
> +v = 202202;
> +cxxmin = 23;
> +  };
> +};
> +
>  ftms = {
>name = fstream_native_handle;
>values = {
> diff --git a/libstdc++-v3/include/bits/version.h 
> b/libstdc++-v3/include/bits/version.h
> index cacd9375cab..1fb1d148459 100644
> --- a/libstdc++-v3/include/bits/version.h
> +++ b/libstdc++-v3/include/bits/version.h
> @@ -1740,29 +1740,18 @@
>  #endif /* !defined(__cpp_lib_reference_from_temporary) && 
> defined(__glibcxx_want_reference_from_temporary) */
>  #undef __glibcxx_want_reference_from_temporary
>  
> -// from version.def line 1443
> -#if !defined(__cpp_lib_to_underlying)
> -# if (__cplusplus >= 202100L)
> -#  define __glibcxx_to_underlying 202102L
> -#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_to_underlying)
> -#   define __cpp_lib_to_underlying 202102L
> +// from version.def line 1452
> +#if !defined(__cpp_lib_ranges_to_container)
> +# if (__cplusplus >= 202100L) && _GLIBCXX_HOSTED
> +#  define __glibcxx_ranges_to_container 202202L
> +#  if defined(__glibcxx_want_all) || 
> defined(__glibcxx_want_ranges_to_container)
> +#   define __cpp_lib_ranges_to_container 202202L
>  

[PATCH 2/2] c++: guard more against undiagnosed error_mark_node [PR112658]

2023-11-28 Thread Patrick Palka
This adds a sanity check to cp_parser_expression_statement similar to
the one in finish_expr_stmt added by r6-6795-g0fd9d4921f7ba2, which
effectively downgrades accepts-invalid/wrong-code bugs like this one
into ice-on-invalid/ice-on-valid ones.

PR c++/112658

gcc/cp/ChangeLog:

* parser.cc (cp_parser_expression_statement): If the statement
is erroneous, make sure we've seen an error.
---
 gcc/cp/parser.cc | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 2464d1a0783..743d6517b09 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -12962,6 +12962,9 @@ cp_parser_expression_statement (cp_parser* parser, tree 
in_statement_expr)
   if (statement == error_mark_node
  && !cp_parser_uncommitted_to_tentative_parse_p (parser))
{
+ /* If we ran into a problem, make sure we complained.  */
+ gcc_assert (seen_error ());
+
  cp_parser_skip_to_end_of_block_or_statement (parser);
  return error_mark_node;
}
-- 
2.43.0.rc1



[PATCH 1/2] c++: casting array prvalue [PR112658, PR94264]

2023-11-28 Thread Patrick Palka
Bootstrapped and regtested on x86-64-pc-linux-gnu, does this look OK for
trunk?

-- >8 --

Here we deem the array-to-pointer conversions in both calls as invalid,
but we fail to issue a diagnostic for the second call, ultimately because
cp_build_c_cast doesn't replay errors from build_const_cast_1.  This means
the second call get silently discarded leading to wrong/unexpected code.

This patch fixes this issue.  I'm not sure if we want to accept these
conversions in the first place (that's PR94264 or at least related to
it), but at least we're more consistent now.

PR c++/112658
PR c++/94264

gcc/cp/ChangeLog:

* typeck.cc (cp_build_c_cast): If we're committed to a const_cast
and the result is erroneous, call build_const_cast_1 a second
time to issue errors.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/initlist-array20.C: New test.
---
 gcc/cp/typeck.cc  |  4 +++-
 gcc/testsuite/g++.dg/cpp0x/initlist-array20.C | 10 ++
 2 files changed, 13 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/initlist-array20.C

diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index e995fb6ddd7..b112bea4d1e 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -9209,6 +9209,8 @@ cp_build_c_cast (location_t loc, tree type, tree expr,
  maybe_warn_about_useless_cast (loc, type, value, complain);
  maybe_warn_about_cast_ignoring_quals (loc, type, complain);
}
+  else if (complain & tf_error)
+   build_const_cast_1 (loc, type, value, tf_error, _p);
   return result;
 }
 
@@ -9244,7 +9246,7 @@ cp_build_c_cast (location_t loc, tree type, tree expr,
 to succeed.  */
   if (!same_type_p (non_reference (type), non_reference (result_type)))
{
- result = build_const_cast_1 (loc, type, result, false, _p);
+ result = build_const_cast_1 (loc, type, result, tf_none, _p);
  gcc_assert (valid_p);
}
   return result;
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-array20.C 
b/gcc/testsuite/g++.dg/cpp0x/initlist-array20.C
new file mode 100644
index 000..967b67023f3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist-array20.C
@@ -0,0 +1,10 @@
+// PR c++/112658
+// { dg-do compile { target c++11 } }
+
+void f(int*);
+
+int main() {
+  using array = int[];
+  f(array{42}); // { dg-error "address of temporary array" }
+  f((int*)array{42}); // { dg-error "address of temporary array" }
+}
-- 
2.43.0.rc1



Re: [PATCH] c++: Implement P2582R1, CTAD from inherited constructors

2023-11-27 Thread Patrick Palka
On Fri, 24 Nov 2023, Patrick Palka wrote:

> On Wed, 22 Nov 2023, Patrick Palka wrote:
> 
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > trunk?
> > 
> > -- >8 --
> > 
> > This patch implements C++23 class template argument deduction from
> > inherited constructors, which is specified in terms of C++20 alias
> > CTAD which we already fully support.  The rule for transforming
> > the return type of an inherited guide is specified in terms of a
> > partially specialized class template, but this patch implements it
> > in a simpler way, performing ahead of time deduction instead of
> > instantiation time deduction.  I wasn't able to find an example for
> > which this implementation strategy makes a difference, but I didn't
> > look very hard.  Support seems good enough to advertise as complete,
> > and there should be no functional change before C++23 mode.
> > 
> > There's a couple of FIXMEs, one in inherited_ctad_tweaks for recognizing
> > more forms of inherited constructors, and one in deduction_guides_for for
> > making the cache aware of base-class dependencies.
> > 
> > There doesn't seem to be a feature-test macro update for this paper.
> > 
> 
> Here's v2 with some minor changes:
> 
>   * set processing_template_decl when rewriting the return type of
> a template guide
>   * rather than adding an out parameter to type_targs_deducible_from,
> just make it return NULL_TREE or the deduced args
>   * add a testcase demonstrating each of the FIXMEs
> 
> -- >8 --
> 
> gcc/cp/ChangeLog:
> 
>   * cp-tree.h (type_targs_deducible_from): Adjust return type.
>   * pt.cc (alias_ctad_tweaks): Handle C++23 inherited CTAD.
>   (inherited_ctad_tweaks): Define.
>   (type_targs_deducible_from): Return the deduced arguments or
>   NULL_TREE instead of a bool.  Handle 'tmpl' being a TREE_LIST
>   representing a synthetic alias template.
>   (ctor_deduction_guides_for): Do inherited_ctad_tweaks for each
>   USING_DECL in C++23 mode.
>   (deduction_guides_for): Add FIXME for stale cache entries in
>   light of inherited CTAD.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp1z/class-deduction67.C: Accept in C++23 mode.
>   * g++.dg/cpp23/class-deduction-inherited1.C: New test.
>   * g++.dg/cpp23/class-deduction-inherited2.C: New test.
>   * g++.dg/cpp23/class-deduction-inherited3.C: New test.
>   * g++.dg/cpp23/class-deduction-inherited4.C: New test.
> ---
>  gcc/cp/cp-tree.h  |   2 +-
>  gcc/cp/pt.cc  | 186 +++---
>  .../g++.dg/cpp1z/class-deduction67.C  |   5 +-
>  .../g++.dg/cpp23/class-deduction-inherited1.C |  38 
>  .../g++.dg/cpp23/class-deduction-inherited2.C |  26 +++
>  .../g++.dg/cpp23/class-deduction-inherited3.C |  16 ++
>  .../g++.dg/cpp23/class-deduction-inherited4.C |  32 +++
>  7 files changed, 272 insertions(+), 33 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp23/class-deduction-inherited1.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp23/class-deduction-inherited2.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp23/class-deduction-inherited3.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp23/class-deduction-inherited4.C
> 
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 7b0b7c6a17e..abc467fb290 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -7457,7 +7457,7 @@ extern tree fn_type_unification (tree, 
> tree, tree,
>bool, bool);
>  extern void mark_decl_instantiated   (tree, int);
>  extern int more_specialized_fn   (tree, tree, int);
> -extern bool type_targs_deducible_from(tree, tree);
> +extern tree type_targs_deducible_from(tree, tree);
>  extern void do_decl_instantiation(tree, tree);
>  extern void do_type_instantiation(tree, tree, tsubst_flags_t);
>  extern bool always_instantiate_p (tree);
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 092e6fdfd36..8b7aa96cf01 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -223,6 +223,9 @@ static void instantiate_body (tree pattern, tree args, 
> tree d, bool nested);
>  static tree maybe_dependent_member_ref (tree, tree, tsubst_flags_t, tree);
>  static void mark_template_arguments_used (tree, tree);
>  static bool uses_outer_template_parms (tree);
> +static tree alias_ctad_tweaks (tree, tree);
> +static tree inherited_ctad_tweaks (tree, tree, tsubst_flags_t);
> +static tree deduction_guides_for (tree, bool&, tsubst

Re: [PATCH] c++: Implement P2582R1, CTAD from inherited constructors

2023-11-24 Thread Patrick Palka
On Wed, 22 Nov 2023, Patrick Palka wrote:

> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk?
> 
> -- >8 --
> 
> This patch implements C++23 class template argument deduction from
> inherited constructors, which is specified in terms of C++20 alias
> CTAD which we already fully support.  The rule for transforming
> the return type of an inherited guide is specified in terms of a
> partially specialized class template, but this patch implements it
> in a simpler way, performing ahead of time deduction instead of
> instantiation time deduction.  I wasn't able to find an example for
> which this implementation strategy makes a difference, but I didn't
> look very hard.  Support seems good enough to advertise as complete,
> and there should be no functional change before C++23 mode.
> 
> There's a couple of FIXMEs, one in inherited_ctad_tweaks for recognizing
> more forms of inherited constructors, and one in deduction_guides_for for
> making the cache aware of base-class dependencies.
> 
> There doesn't seem to be a feature-test macro update for this paper.
> 

Here's v2 with some minor changes:

  * set processing_template_decl when rewriting the return type of
a template guide
  * rather than adding an out parameter to type_targs_deducible_from,
just make it return NULL_TREE or the deduced args
  * add a testcase demonstrating each of the FIXMEs

-- >8 --

gcc/cp/ChangeLog:

* cp-tree.h (type_targs_deducible_from): Adjust return type.
* pt.cc (alias_ctad_tweaks): Handle C++23 inherited CTAD.
(inherited_ctad_tweaks): Define.
(type_targs_deducible_from): Return the deduced arguments or
NULL_TREE instead of a bool.  Handle 'tmpl' being a TREE_LIST
representing a synthetic alias template.
(ctor_deduction_guides_for): Do inherited_ctad_tweaks for each
USING_DECL in C++23 mode.
(deduction_guides_for): Add FIXME for stale cache entries in
light of inherited CTAD.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/class-deduction67.C: Accept in C++23 mode.
* g++.dg/cpp23/class-deduction-inherited1.C: New test.
* g++.dg/cpp23/class-deduction-inherited2.C: New test.
* g++.dg/cpp23/class-deduction-inherited3.C: New test.
* g++.dg/cpp23/class-deduction-inherited4.C: New test.
---
 gcc/cp/cp-tree.h  |   2 +-
 gcc/cp/pt.cc  | 186 +++---
 .../g++.dg/cpp1z/class-deduction67.C  |   5 +-
 .../g++.dg/cpp23/class-deduction-inherited1.C |  38 
 .../g++.dg/cpp23/class-deduction-inherited2.C |  26 +++
 .../g++.dg/cpp23/class-deduction-inherited3.C |  16 ++
 .../g++.dg/cpp23/class-deduction-inherited4.C |  32 +++
 7 files changed, 272 insertions(+), 33 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp23/class-deduction-inherited1.C
 create mode 100644 gcc/testsuite/g++.dg/cpp23/class-deduction-inherited2.C
 create mode 100644 gcc/testsuite/g++.dg/cpp23/class-deduction-inherited3.C
 create mode 100644 gcc/testsuite/g++.dg/cpp23/class-deduction-inherited4.C

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 7b0b7c6a17e..abc467fb290 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7457,7 +7457,7 @@ extern tree fn_type_unification   (tree, 
tree, tree,
 bool, bool);
 extern void mark_decl_instantiated (tree, int);
 extern int more_specialized_fn (tree, tree, int);
-extern bool type_targs_deducible_from  (tree, tree);
+extern tree type_targs_deducible_from  (tree, tree);
 extern void do_decl_instantiation  (tree, tree);
 extern void do_type_instantiation  (tree, tree, tsubst_flags_t);
 extern bool always_instantiate_p   (tree);
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 092e6fdfd36..8b7aa96cf01 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -223,6 +223,9 @@ static void instantiate_body (tree pattern, tree args, tree 
d, bool nested);
 static tree maybe_dependent_member_ref (tree, tree, tsubst_flags_t, tree);
 static void mark_template_arguments_used (tree, tree);
 static bool uses_outer_template_parms (tree);
+static tree alias_ctad_tweaks (tree, tree);
+static tree inherited_ctad_tweaks (tree, tree, tsubst_flags_t);
+static tree deduction_guides_for (tree, bool&, tsubst_flags_t);
 
 /* Make the current scope suitable for access checking when we are
processing T.  T can be FUNCTION_DECL for instantiated function
@@ -29736,8 +29739,6 @@ is_spec_or_derived (tree etype, tree tmpl)
   return !err;
 }
 
-static tree alias_ctad_tweaks (tree, tree);
-
 /* Return a C++20 aggregate deduction candidate for TYPE initialized from
INIT.  */
 
@@ -29842,7 +29843,13 @@ maybe_aggr_guide (tree tmpl, tree init, 
vec *args)
 }
 
 /* UGUIDES are the deduction guides for the

[PATCH] c++/modules: alias CTAD and specializations table

2023-11-24 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?

-- >8 --

A rewritten guide for alias CTAD isn't really a specialization of the
original guide, so we shouldn't register it as such.  This avoids an ICE
in the below modules testcase which otherwise tries to inspect the
rewritten guide's empty DECL_CONTEXT.  It also preemptively avoids an
ICE in modules/concept-6 in C++23 mode with the inherited CTAD patch.

* pt.cc (alias_ctad_tweaks): Pass use_spec_table=false to
tsubst_decl.

gcc/testsuite/ChangeLog:

* g++.dg/modules/concept-8.h: New test.
* g++.dg/modules/concept-8_a.H: New test.
* g++.dg/modules/concept-8_b.C: New test.
---
 gcc/cp/pt.cc   |  3 ++-
 gcc/testsuite/g++.dg/modules/concept-8.h   | 14 ++
 gcc/testsuite/g++.dg/modules/concept-8_a.H |  5 +
 gcc/testsuite/g++.dg/modules/concept-8_b.C |  8 
 4 files changed, 29 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/modules/concept-8.h
 create mode 100644 gcc/testsuite/g++.dg/modules/concept-8_a.H
 create mode 100644 gcc/testsuite/g++.dg/modules/concept-8_b.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 4f93150c5d7..2cfe1da5e07 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -30015,7 +30015,8 @@ alias_ctad_tweaks (tree tmpl, tree uguides)
  /* Parms are to have DECL_CHAIN tsubsted, which would be skipped
 if cp_unevaluated_operand.  */
  cp_evaluated ev;
- g = tsubst_decl (DECL_TEMPLATE_RESULT (f), targs, complain);
+ g = tsubst_decl (DECL_TEMPLATE_RESULT (f), targs, complain,
+  /*use_spec_table=*/false);
}
  if (g == error_mark_node)
continue;
diff --git a/gcc/testsuite/g++.dg/modules/concept-8.h 
b/gcc/testsuite/g++.dg/modules/concept-8.h
new file mode 100644
index 000..a25f9b752fd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/concept-8.h
@@ -0,0 +1,14 @@
+// A version of concept-6.h using an alias template + alias CTAD
+
+template
+struct Base
+{
+  Base (const _Callable &)
+requires true
+  {}
+};
+
+template requires true
+using Derived = Base<_Callable>;
+
+inline Derived all = [] (auto&& __r) {};
diff --git a/gcc/testsuite/g++.dg/modules/concept-8_a.H 
b/gcc/testsuite/g++.dg/modules/concept-8_a.H
new file mode 100644
index 000..da0467781c1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/concept-8_a.H
@@ -0,0 +1,5 @@
+// { dg-require-effective-target c++20 }
+// { dg-additional-options "-fmodule-header -fconcepts" }
+// { dg-module-cmi {} }
+
+#include "concept-8.h"
diff --git a/gcc/testsuite/g++.dg/modules/concept-8_b.C 
b/gcc/testsuite/g++.dg/modules/concept-8_b.C
new file mode 100644
index 000..9a9f014ee09
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/concept-8_b.C
@@ -0,0 +1,8 @@
+// { dg-require-effective-target c++20 }
+// { dg-additional-options "-fmodules-ts -fconcepts -fdump-lang-module-alias 
-fno-module-lazy" }
+
+#include "concept-8.h"
+import "concept-8_a.H";
+
+// { dg-final { scan-lang-dump-times {named merge key \(matched\) 
function_decl:'::Base<::._anon_0>::__ct '} 2 module } }
+// { dg-final { scan-lang-dump-not {merge key \(new\)} module } }
-- 
2.43.0.rc1



Re: [PATCH] c++: Clear uninstantiated friend flag when instantiating [PR104234]

2023-11-23 Thread Patrick Palka
On Thu, 23 Nov 2023, Nathaniel Shead wrote:

> Bootstrapped and regtested on x86_64-pc-linux-gnu. I don't have write
> access.
> 
> -- >8 --
> 
> Otherwise attempting to get the originating module declaration ICEs
> because the DECL_CHAIN of an instantiated friend template is no longer
> its context.

Thanks for the patch!  I arrived at a similar fix back in January[1],
which Nathan reviewed[2], which then fell through the cracks...  My
patch was perhaps too ambitious as it tried to fix the ICE as well
as a follow-up module attachment issue.  But just clearing
DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (either in tsubst_template_decl or
more narrowly in tsubst_friend_class) seems pretty clearly correct and
fixes the reported ICEs so LGTM :) Thanks again!

[1]: https://gcc.gnu.org/pipermail/gcc-patches/2023-January/610593.html
[2]: https://gcc.gnu.org/pipermail/gcc-patches/2023-February/611215.html

> 
>   PR c++/104234
> PR c++/112580
> 
> gcc/cp/ChangeLog:
> 
>   * pt.cc (tsubst_template_decl):
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/modules/pr104234.C: New test.
> 
> Signed-off-by: Nathaniel Shead 
> ---
>  gcc/cp/pt.cc|  2 ++
>  gcc/testsuite/g++.dg/modules/pr104234.C | 16 
>  2 files changed, 18 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/modules/pr104234.C
> 
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index ed681afb5d4..5e10a523e1a 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -14789,6 +14789,8 @@ tsubst_template_decl (tree t, tree args, 
> tsubst_flags_t complain,
>if (PRIMARY_TEMPLATE_P (t))
>  DECL_PRIMARY_TEMPLATE (r) = r;
>  
> +  DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (r) = false;
> +
>if (!lambda_fntype && !class_p)
>  {
>/* Record this non-type partial instantiation.  */
> diff --git a/gcc/testsuite/g++.dg/modules/pr104234.C 
> b/gcc/testsuite/g++.dg/modules/pr104234.C
> new file mode 100644
> index 000..d81f0d435bc
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/modules/pr104234.C
> @@ -0,0 +1,16 @@
> +// PR c++/104234
> +// { dg-additional-options "-fmodules-ts" }
> +
> +template  struct _Node_handle_common {
> +  template  friend class _Rb_tree;
> +};
> +struct _Hashtable {
> +  using node_type = _Node_handle_common;
> +  node_type __trans_tmp_1;
> +};
> +template  class _Rb_tree {
> +  struct _Rb_tree_impl {
> +_Rb_tree_impl();
> +  } _M_impl;
> +};
> +_Rb_tree _M_tmap_;
> -- 
> 2.42.0
> 
> 



[PATCH] c++: alias template of non-template class [PR112633]

2023-11-22 Thread Patrick Palka
Bootstrapped and regtested on x86-64-pc-linux-gnu, does this look OK for
trunk/13?

-- >8 --

The entering_scope adjustment in tsubst_aggr_type assumes if an alias is
dependent, then so is the aliased type (and therefore it has template info)
but that's not true for the dependent alias template specialization ty1
below which aliases the non-template class A.

PR c++/112633

gcc/cp/ChangeLog:

* pt.cc (tsubst_aggr_type): Handle empty TYPE_TEMPLATE_INFO
in the entering_scope adjustment.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/alias-decl-75.C: New test.
---
 gcc/cp/pt.cc   |  1 +
 gcc/testsuite/g++.dg/cpp0x/alias-decl-75.C | 13 +
 2 files changed, 14 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-75.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index ed681afb5d4..68ce4a87372 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -13976,6 +13976,7 @@ tsubst_aggr_type (tree t,
   if (entering_scope
  && CLASS_TYPE_P (t)
  && dependent_type_p (t)
+ && TYPE_TEMPLATE_INFO (t)
  && TYPE_CANONICAL (t) == TREE_TYPE (TYPE_TI_TEMPLATE (t)))
t = TYPE_CANONICAL (t);
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-75.C 
b/gcc/testsuite/g++.dg/cpp0x/alias-decl-75.C
new file mode 100644
index 000..1a73a99856e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-75.C
@@ -0,0 +1,13 @@
+// PR c++/112633
+// { dg-do compile { target c++11 } }
+
+struct A { using type = void; };
+
+template
+using ty1 = A;
+
+template
+using ty2 = typename ty1::type;
+
+template
+ty2 f();
-- 
2.43.0.rc1



[PATCH] c++: Implement P2582R1, CTAD from inherited constructors

2023-11-22 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?

-- >8 --

This patch implements C++23 class template argument deduction from
inherited constructors, which is specified in terms of C++20 alias
CTAD which we already fully support.  The rule for transforming
the return type of an inherited guide is specified in terms of a
partially specialized class template, but this patch implements it
in a simpler way, performing ahead of time deduction instead of
instantiation time deduction.  I wasn't able to find an example for
which this implementation strategy makes a difference, but I didn't
look very hard.  Support seems good enough to advertise as complete,
and there should be no functional change before C++23 mode.

There's a couple of FIXMEs, one in inherited_ctad_tweaks for recognizing
more forms of inherited constructors, and one in deduction_guides_for for
making the cache aware of base-class dependencies.

There doesn't seem to be a feature-test macro update for this paper.

gcc/cp/ChangeLog:

* cp-tree.h (type_targs_deducible_from): Adjust declaration.
* pt.cc (alias_ctad_tweaks): Handle C++23 inherited CTAD.
(inherited_ctad_tweaks): Define.
(type_targs_deducible_from): Add defaulted 'targs_out' parameter.
Handle 'tmpl' being a TREE_LIST representing a synthetic alias
template.  Set 'targs_out' upon success.
(ctor_deduction_guides_for): Do inherited_ctad_tweaks for each
USING_DECL in C++23 mode.
(deduction_guides_for): Add FIXME for stale cache entries in
light of inherited CTAD.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/class-deduction67.C: Accept in C++23 mode.
* g++.dg/cpp23/class-deduction-inherited1.C: New test.
* g++.dg/cpp23/class-deduction-inherited2.C: New test.
* g++.dg/cpp23/class-deduction-inherited3.C: New test.
---
 gcc/cp/cp-tree.h  |   2 +-
 gcc/cp/pt.cc  | 176 +++---
 .../g++.dg/cpp1z/class-deduction67.C  |   5 +-
 .../g++.dg/cpp23/class-deduction-inherited1.C |  36 
 .../g++.dg/cpp23/class-deduction-inherited2.C |  26 +++
 .../g++.dg/cpp23/class-deduction-inherited3.C |  16 ++
 6 files changed, 231 insertions(+), 30 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp23/class-deduction-inherited1.C
 create mode 100644 gcc/testsuite/g++.dg/cpp23/class-deduction-inherited2.C
 create mode 100644 gcc/testsuite/g++.dg/cpp23/class-deduction-inherited3.C

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 1fa710d7154..633d58b1d12 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7434,7 +7434,7 @@ extern tree fn_type_unification   (tree, 
tree, tree,
 bool, bool);
 extern void mark_decl_instantiated (tree, int);
 extern int more_specialized_fn (tree, tree, int);
-extern bool type_targs_deducible_from  (tree, tree);
+extern bool type_targs_deducible_from  (tree, tree, tree * = nullptr);
 extern void do_decl_instantiation  (tree, tree);
 extern void do_type_instantiation  (tree, tree, tsubst_flags_t);
 extern bool always_instantiate_p   (tree);
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 324f6f01555..75f5bc9bed5 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -223,6 +223,9 @@ static void instantiate_body (tree pattern, tree args, tree 
d, bool nested);
 static tree maybe_dependent_member_ref (tree, tree, tsubst_flags_t, tree);
 static void mark_template_arguments_used (tree, tree);
 static bool uses_outer_template_parms (tree);
+static tree alias_ctad_tweaks (tree, tree);
+static tree inherited_ctad_tweaks (tree, tree, tsubst_flags_t);
+static tree deduction_guides_for (tree, bool&, tsubst_flags_t);
 
 /* Make the current scope suitable for access checking when we are
processing T.  T can be FUNCTION_DECL for instantiated function
@@ -29753,8 +29756,6 @@ is_spec_or_derived (tree etype, tree tmpl)
   return !err;
 }
 
-static tree alias_ctad_tweaks (tree, tree);
-
 /* Return a C++20 aggregate deduction candidate for TYPE initialized from
INIT.  */
 
@@ -29859,7 +29860,13 @@ maybe_aggr_guide (tree tmpl, tree init, 
vec *args)
 }
 
 /* UGUIDES are the deduction guides for the underlying template of alias
-   template TMPL; adjust them to be deduction guides for TMPL.  */
+   template TMPL; adjust them to be deduction guides for TMPL.
+
+   This routine also handles C++23 inherited CTAD, in which case TMPL is a
+   TREE_LIST representing a synthetic alias template whose TREE_PURPOSE is
+   the template parameter list of the alias template (equivalently, of the
+   derived class) and TREE_VALUE the defining-type-id (equivalently, the
+   base whose guides we're inheriting).  UGUIDES are the base's guides.  */
 
 static tree
 alias_ctad_tweaks (tree tmpl, tree uguides)
@@ -29903,13 +29910,30 @@ alias_ctad_tweaks 

[pushed] c++: add fixed testcases [PR98614, PR104802]

2023-11-16 Thread Patrick Palka
Tested on x86_64-pc-linux-gnu, pushed to trunk.

-- >8 --

Both of these PRs are fixed by r12-1403-gc4e50e500da7692a.

PR c++/98614
PR c++/104802

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/nontype-auto22.C: New test.
* g++.dg/cpp2a/concepts-partial-spec14.C: New test.
---
 gcc/testsuite/g++.dg/cpp1z/nontype-auto22.C | 17 +
 .../g++.dg/cpp2a/concepts-partial-spec14.C  | 10 ++
 2 files changed, 27 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/cpp1z/nontype-auto22.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec14.C

diff --git a/gcc/testsuite/g++.dg/cpp1z/nontype-auto22.C 
b/gcc/testsuite/g++.dg/cpp1z/nontype-auto22.C
new file mode 100644
index 000..1882d2586d5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/nontype-auto22.C
@@ -0,0 +1,17 @@
+// PR c++/104802
+// { dg-do compile { target c++17 } }
+
+template
+struct S {
+  template
+  void operator()() const {}
+};
+
+struct weird_ {
+  int operator&() const { return 123; }
+} const weird {};
+
+int main() {
+  S s {};
+  s();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec14.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec14.C
new file mode 100644
index 000..c94b4013340
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec14.C
@@ -0,0 +1,10 @@
+// PR c++/98614
+// { dg-do compile { target c++20 } }
+
+template
+struct A;
+
+template requires true
+struct A {
+  A(A const&) = default;
+};
-- 
2.43.0.rc1



[PATCH] c++: constantness of call to function pointer [PR111703]

2023-11-15 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
for trunk/13/12 (to match the PR107939 / r13-6525-ge09bc034d1b4d6 backports)?

-- >8 --

potential_constant_expression for a CALL_EXPR to a non-overload tests
FUNCTION_POINTER_TYPE_P on the callee rather than on the type of the
callee, which means we always pass want_rval=any when recursing and so
may fail to properly treat a non-constant function pointer callee as such.
Fixing this turns out to further work around the PR111703 issue.

PR c++/111703
PR c++/107939

gcc/cp/ChangeLog:

* constexpr.cc (potential_constant_expression_1) :
Fix FUNCTION_POINTER_TYPE_P test.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts-fn8.C: Extend test.
* g++.dg/diagnostic/constexpr4.C: New test.
---
 gcc/cp/constexpr.cc  | 4 +++-
 gcc/testsuite/g++.dg/cpp2a/concepts-fn8.C| 2 ++
 gcc/testsuite/g++.dg/diagnostic/constexpr4.C | 9 +
 3 files changed, 14 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/diagnostic/constexpr4.C

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 8a6b210144a..5ecc30117a1 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -9547,7 +9547,9 @@ potential_constant_expression_1 (tree t, bool want_rval, 
bool strict, bool now,
  }
else if (fun)
   {
-   if (RECUR (fun, FUNCTION_POINTER_TYPE_P (fun) ? rval : any))
+   if (RECUR (fun, (TREE_TYPE (fun)
+&& FUNCTION_POINTER_TYPE_P (TREE_TYPE (fun))
+? rval : any)))
  /* Might end up being a constant function pointer.  But it
 could also be a function object with constexpr op(), so
 we pass 'any' so that the underlying VAR_DECL is deemed
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-fn8.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-fn8.C
index 3f63a5b28d7..c63d26c931d 100644
--- a/gcc/testsuite/g++.dg/cpp2a/concepts-fn8.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-fn8.C
@@ -15,10 +15,12 @@ struct P {
 };
 
 void (*f)(P);
+P (*h)(P);
 
 template
 constexpr bool g() {
   P x;
   f(x); // { dg-bogus "from here" }
+  f(h(x)); // { dg-bogus "from here" }
   return true;
 }
diff --git a/gcc/testsuite/g++.dg/diagnostic/constexpr4.C 
b/gcc/testsuite/g++.dg/diagnostic/constexpr4.C
new file mode 100644
index 000..f971f533b08
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/constexpr4.C
@@ -0,0 +1,9 @@
+// Verify we diagnose a call to a non-constant function pointer ahead of time.
+// { dg-do compile { target c++11 } }
+
+int (*f)(int);
+
+template
+void g() {
+  static_assert(f(N) == 0, ""); // { dg-error "non-constant|'f' is not usable" 
}
+}
-- 
2.43.0.rc1



[PATCH] c++: partially inst requires-expr in noexcept-spec [PR101043]

2023-11-14 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?

-- >8 --

Here we're ICEing from strip_typedefs for the partially instantiated
requires-expression when walking its REQUIRES_EXPR_EXTRA_ARGS since it's
a TREE_LIST with non-empty TREE_PURPOSE (to hold the captured local
specialization 't' as per build_extra_args) which strip_typedefs doesn't
expect.

We can probably skip walking REQUIRES_EXPR_EXTRA_ARGS at all since it
shouldn't contain any typedefs in the first place, but it seems safer
and more generally useful to just teach strip_typedefs to handle non-empty
TREE_PURPOSE the obvious way.  (The handling asserted TREE_PURPOSE was
empty ever since inception i.e. r189298.)

PR c++/101043

gcc/cp/ChangeLog:

* tree.cc (strip_typedefs_expr) : Handle
non-empty TREE_PURPOSE.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts-requires37.C: New test.
---
 gcc/cp/tree.cc| 19 ---
 .../g++.dg/cpp2a/concepts-requires37.C| 11 +++
 2 files changed, 23 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-requires37.C

diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index dc4126f935c..0736e8d8f48 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -1911,19 +1911,24 @@ strip_typedefs_expr (tree t, bool *remove_attributes, 
unsigned int flags)
 case TREE_LIST:
   {
bool changed = false;
-   releasing_vec vec;
+   auto_vec vec;
r = t;
for (; t; t = TREE_CHAIN (t))
  {
-   gcc_assert (!TREE_PURPOSE (t));
-   tree elt = strip_typedefs (TREE_VALUE (t),
-  remove_attributes, flags);
-   if (elt != TREE_VALUE (t))
+   tree purpose = strip_typedefs (TREE_PURPOSE (t),
+  remove_attributes, flags);
+   tree value = strip_typedefs (TREE_VALUE (t),
+remove_attributes, flags);
+   if (purpose != TREE_PURPOSE (t) || value != TREE_VALUE (t))
  changed = true;
-   vec_safe_push (vec, elt);
+   vec.safe_push ({purpose, value});
  }
if (changed)
- r = build_tree_list_vec (vec);
+ {
+   r = NULL_TREE;
+   for (int i = vec.length () - 1; i >= 0; i--)
+ r = tree_cons (vec[i].first, vec[i].second, r);
+ }
return r;
   }
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires37.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-requires37.C
new file mode 100644
index 000..72dad77fea1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires37.C
@@ -0,0 +1,11 @@
+// PR c++/101043
+// { dg-do compile { target c++20 } }
+
+template
+void f(T t) {
+  [&](auto) noexcept(requires { { t.g() }; }) { }(0);
+}
+
+int main() {
+  f(0);
+}
-- 
2.43.0.rc1



[PATCH] c++: direct enum init from type-dep elt [PR112515]

2023-11-14 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
OK for trunk?

-- >8 --

The NON_DEPENDENT_EXPR removal exposed that is_direct_enum_init may end
up checking convertibility of a type-dependent argument.

PR c++/112515

gcc/cp/ChangeLog:

* decl.cc (is_direct_enum_init): Return false if the single
element is type-dependent.

gcc/testsuite/ChangeLog:

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

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 4a07c7e879b..4be4847810a 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -6614,6 +6614,7 @@ is_direct_enum_init (tree type, tree init)
   && CONSTRUCTOR_NELTS (init) == 1
   /* DR 2374: The single element needs to be implicitly
 convertible to the underlying type of the enum.  */
+  && !type_dependent_expression_p (CONSTRUCTOR_ELT (init, 0)->value)
   && can_convert_arg (ENUM_UNDERLYING_TYPE (type),
  TREE_TYPE (CONSTRUCTOR_ELT (init, 0)->value),
  CONSTRUCTOR_ELT (init, 0)->value,
diff --git a/gcc/testsuite/g++.dg/template/non-dependent30.C 
b/gcc/testsuite/g++.dg/template/non-dependent30.C
new file mode 100644
index 000..32d48e44c09
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/non-dependent30.C
@@ -0,0 +1,9 @@
+// PR c++/112515
+// { dg-do compile { target c++11 } }
+
+enum E : int { };
+
+template
+E f(T t) {
+  return E{t.e};
+}
-- 
2.43.0.rc1



[PATCH] c++: decltype of (non-captured variable) [PR83167]

2023-11-14 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?

-- >8 --

For decltype((x)) within a lambda where x is not captured, we dubiously
require that the lambda has a capture default, unlike for decltype(x).
This patch fixes this inconsistency; I couldn't find a justification for
it in the standard.

PR c++/83167

gcc/cp/ChangeLog:

* semantics.cc (finish_decltype_type): If capture_decltype
returns NULL_TREE, fall back to the ordinary code path.
(capture_decltype): Return NULL_TREE if the lambda has no
capture-default.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/lambda/lambda-decltype4.C: New test.
---
 gcc/cp/semantics.cc   |  6 +++---
 .../g++.dg/cpp0x/lambda/lambda-decltype4.C| 15 +++
 2 files changed, 18 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-decltype4.C

diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 8090c71809f..6fdd6c45972 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -11732,7 +11732,8 @@ finish_decltype_type (tree expr, bool 
id_expression_or_member_access_p,
/* If the expression is just "this", we want the
   cv-unqualified pointer for the "this" type.  */
type = TYPE_MAIN_VARIANT (TREE_TYPE (expr));
-  else
+
+  if (!type)
{
  /* Otherwise, where T is the type of e, if e is an lvalue,
 decltype(e) is defined as T&; if an xvalue, T&&; otherwise, T. */
@@ -12639,8 +12640,7 @@ capture_decltype (tree decl)
 switch (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lam))
   {
   case CPLD_NONE:
-   error ("%qD is not captured", decl);
-   return error_mark_node;
+   return NULL_TREE;
 
   case CPLD_COPY:
type = TREE_TYPE (decl);
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-decltype4.C 
b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-decltype4.C
new file mode 100644
index 000..0062d7b8672
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-decltype4.C
@@ -0,0 +1,15 @@
+// PR c++/83167
+// { dg-do compile { target c++11 } }
+
+int main() {
+  int x;
+  const int y = 42;
+
+  [] {
+using ty1 = decltype((x));
+using ty1 = int&;
+
+using ty2 = decltype((y));
+using ty2 = const int&;
+  };
+}
-- 
2.43.0.rc1



Re: [PATCH] c++: non-dependent .* folding [PR112427]

2023-11-14 Thread Patrick Palka
On Fri, 10 Nov 2023, Jason Merrill wrote:

> On 11/10/23 10:28, Patrick Palka wrote:
> > On Fri, 10 Nov 2023, Patrick Palka wrote:
> > 
> > > On Thu, 9 Nov 2023, Jason Merrill wrote:
> > > 
> > > > On 11/8/23 16:59, Patrick Palka wrote:
> > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
> > > > > for
> > > > > trunk?
> > > > > 
> > > > > -- >8 --
> > > > > 
> > > > > Here when building up the non-dependent .* expression, we crash from
> > > > > fold_convert on 'b.a' due to this (templated) COMPONENT_REF having an
> > > > > IDENTIFIER_NODE instead of FIELD_DECL operand that middle-end routines
> > > > > expect.  Like in r14-4899-gd80a26cca02587, this patch fixes this by
> > > > > replacing the problematic piecemeal folding with a single call to
> > > > > cp_fully_fold.
> > > > > 
> > > > >   PR c++/112427
> > > > > 
> > > > > gcc/cp/ChangeLog:
> > > > > 
> > > > >   * typeck2.cc (build_m_component_ref): Use cp_convert, build2
> > > > > and
> > > > >   cp_fully_fold instead of fold_build_pointer_plus and
> > > > > fold_convert.
> > > > 
> > > > > gcc/testsuite/ChangeLog:
> > > > > 
> > > > >   * g++.dg/template/non-dependent29.C: New test.
> > > > > ---
> > > > >gcc/cp/typeck2.cc   |  5 -
> > > > >gcc/testsuite/g++.dg/template/non-dependent29.C | 13 +
> > > > >2 files changed, 17 insertions(+), 1 deletion(-)
> > > > >create mode 100644 gcc/testsuite/g++.dg/template/non-dependent29.C
> > > > > 
> > > > > diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc
> > > > > index 309903afed8..208004221da 100644
> > > > > --- a/gcc/cp/typeck2.cc
> > > > > +++ b/gcc/cp/typeck2.cc
> > > > > @@ -2378,7 +2378,10 @@ build_m_component_ref (tree datum, tree
> > > > > component,
> > > > > tsubst_flags_t complain)
> > > > >  /* Build an expression for "object + offset" where offset is
> > > > > the
> > > > >value stored in the pointer-to-data-member.  */
> > > > >  ptype = build_pointer_type (type);
> > > > > -  datum = fold_build_pointer_plus (fold_convert (ptype, datum),
> > > > > component);
> > > > > +  datum = cp_convert (ptype, datum, complain);
> > > > > +  datum = build2 (POINTER_PLUS_EXPR, ptype,
> > > > > +   datum, convert_to_ptrofftype (component));
> > > > 
> > > > We shouldn't need to build the POINTER_PLUS_EXPR at all in template
> > > > context.
> > > > OK with that change.
> > > 
> > > Hmm, that seems harmless at first glance, but I noticed
> > > build_min_non_dep (called from build_x_binary_op in this case) is
> > > careful to propagate TREE_SIDE_EFFECTS of the given tree, and so eliding
> > > POINTER_PLUS_EXPR here could potentially mean that the tree we
> > > ultimately return from build_x_binary_op when in a template context has
> > > TREE_SIDE_EFFECTS not set when it used to.  Shall we still elide the
> > > POINTER_PLUS_EXPR in a template context despite this?
> 
> True, we would need build_min_non_dep to also get TREE_SIDE_EFFECTS from the
> operands.  That might be useful in general for similar situations?
> 
> I also note that convert_to_ptrofftype uses fold_convert, so the new code
> could have the same problem if the pointer to member operand is also a
> COMPONENT_REF.

Ah, makes sense...  How does the following look then?  I'm not sure if
we still want to replace fold_build_pointer_plus with build2 if we're
not going to use that code path in a template context?  Bootstrapped and
regtested on x86_64-pc-linux-gnu.

-- >8 --
-
Subject: [PATCH] c++: non-dependent .* operand folding [PR112427]

Here when building up the non-dependent .* expression, we crash from
fold_convert on 'b.a' due to this (templated) COMPONENT_REF having an
IDENTIFIER_NODE instead of FIELD_DECL operand that middle-end routines
expect.  Like in r14-4899-gd80a26cca02587, this patch fixes this by
replacing the problematic piecemeal folding with a single call to
cp_fully_fold.  Additionally, don't bother building POINTER_PLUS_EXPR
in a template context.  This means the returned non-dependent tr

Re: [PATCH] c++: fix tf_decltype manipulation for COMPOUND_EXPR

2023-11-10 Thread Patrick Palka
On Fri, 10 Nov 2023, Jason Merrill wrote:

> On 11/10/23 12:25, Patrick Palka wrote:
> > On Thu, 9 Nov 2023, Jason Merrill wrote:
> > 
> > > On 11/7/23 10:08, Patrick Palka wrote:
> > > > bootstrapped and regtested on x86_64-pc-linxu-gnu, does this look OK for
> > > > trunk?
> > > > 
> > > > -- >8 --
> > > > 
> > > > In the COMPOUND_EXPR case of tsubst_expr, we were redundantly clearing
> > > > the tf_decltype flag when substituting the LHS and also neglecting to
> > > > propagate it when substituting the RHS.  This patch corrects this flag
> > > > manipulation, which allows us to accept the below testcase.
> > > > 
> > > > gcc/cp/ChangeLog:
> > > > 
> > > > * pt.cc (tsubst_expr) : Don't redundantly
> > > > clear tf_decltype when substituting the LHS.  Propagate
> > > > tf_decltype when substituting the RHS.
> > > > 
> > > > gcc/testsuite/ChangeLog:
> > > > 
> > > > * g++.dg/cpp0x/decltype-call7.C: New test.
> > > > ---
> > > >gcc/cp/pt.cc| 9 -
> > > >gcc/testsuite/g++.dg/cpp0x/decltype-call7.C | 9 +
> > > >2 files changed, 13 insertions(+), 5 deletions(-)
> > > >create mode 100644 gcc/testsuite/g++.dg/cpp0x/decltype-call7.C
> > > > 
> > > > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > > > index 521749df525..5f879287a58 100644
> > > > --- a/gcc/cp/pt.cc
> > > > +++ b/gcc/cp/pt.cc
> > > > @@ -20382,11 +20382,10 @@ tsubst_expr (tree t, tree args, tsubst_flags_t
> > > > complain, tree in_decl)
> > > >  case COMPOUND_EXPR:
> > > >  {
> > > > -   tree op0 = tsubst_expr (TREE_OPERAND (t, 0), args,
> > > > -   complain & ~tf_decltype, in_decl);
> > > > -   RETURN (build_x_compound_expr (EXPR_LOCATION (t),
> > > > -  op0,
> > > > -  RECUR (TREE_OPERAND (t, 1)),
> > > > +   tree op0 = RECUR (TREE_OPERAND (t, 0));
> > > > +   tree op1 = tsubst_expr (TREE_OPERAND (t, 1), args,
> > > > +   complain|decltype_flag, in_decl);
> > > > +   RETURN (build_x_compound_expr (EXPR_LOCATION (t), op0, op1,
> > > >templated_operator_saved_lookups
> > > > (t),
> > > >complain|decltype_flag));
> > > 
> > > Hmm, passing decltype_flag to both op1 and the , is concerning.  Can you
> > > add a
> > > test with overloaded operator, where the RHS is a class with a destructor?
> > 
> > I'm not sure if this is what you had in mind, but indeed with this patch
> > we reject the following with an error outside the immediate context:
> > 
> >  struct B { ~B() = delete; };
> >  template B f();
> > 
> >  void operator,(int, const B&);
> > 
> >  template decltype(42, f()) g(int) = delete; // #1
> >  template void g(...); // #2
> > 
> >  int main() {
> >g(0); // should select #2
> >  }
> > 
> > gcc/testsuite/g++.dg/cpp0x/decltype-call8.C: In substitution of
> > ‘template decltype ((42, f())) g(int) [with T = B]’:
> > gcc/testsuite/g++.dg/cpp0x/decltype-call8.C:12:7:   required from here
> > 12 |   g(0);
> >|   ^~~
> > gcc/testsuite/g++.dg/cpp0x/decltype-call8.C:8:30: error: use of deleted
> > function ‘B::~B()’
> >  8 | template decltype(42, f()) g(int) = delete; // #1
> >|~~^~~~
> > gcc/testsuite/g++.dg/cpp0x/decltype-call8.C:3:12: note: declared here
> >  3 | struct B { ~B() = delete; };
> >|^
> > 
> > Ultimately because unary_complex_lvalue isn't SFINAE-enabled.
> 
> Please elaborate; my understanding is that unary_complex_lvalue is supposed to
> be a semantically neutral transformation.

Since tf_decltype is now also set when substituting op1 i.e. f(),
substitution yields a bare CALL_EXPR with no temporary materialization.
The problematic unary_complex_lvalue call happens when binding
the reference parameter 'const B&' to this bare CALL_EXPR.  We
take its address via cp_build_addr_expr, which tries
unary_complex_lvalue.  The CALL_EXPR handling in unary_complex

Re: [PATCH] c++: fix tf_decltype manipulation for COMPOUND_EXPR

2023-11-10 Thread Patrick Palka
On Thu, 9 Nov 2023, Jason Merrill wrote:

> On 11/7/23 10:08, Patrick Palka wrote:
> > bootstrapped and regtested on x86_64-pc-linxu-gnu, does this look OK for
> > trunk?
> > 
> > -- >8 --
> > 
> > In the COMPOUND_EXPR case of tsubst_expr, we were redundantly clearing
> > the tf_decltype flag when substituting the LHS and also neglecting to
> > propagate it when substituting the RHS.  This patch corrects this flag
> > manipulation, which allows us to accept the below testcase.
> > 
> > gcc/cp/ChangeLog:
> > 
> > * pt.cc (tsubst_expr) : Don't redundantly
> > clear tf_decltype when substituting the LHS.  Propagate
> > tf_decltype when substituting the RHS.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/cpp0x/decltype-call7.C: New test.
> > ---
> >   gcc/cp/pt.cc| 9 -
> >   gcc/testsuite/g++.dg/cpp0x/decltype-call7.C | 9 +
> >   2 files changed, 13 insertions(+), 5 deletions(-)
> >   create mode 100644 gcc/testsuite/g++.dg/cpp0x/decltype-call7.C
> > 
> > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > index 521749df525..5f879287a58 100644
> > --- a/gcc/cp/pt.cc
> > +++ b/gcc/cp/pt.cc
> > @@ -20382,11 +20382,10 @@ tsubst_expr (tree t, tree args, tsubst_flags_t
> > complain, tree in_decl)
> > case COMPOUND_EXPR:
> > {
> > -   tree op0 = tsubst_expr (TREE_OPERAND (t, 0), args,
> > -   complain & ~tf_decltype, in_decl);
> > -   RETURN (build_x_compound_expr (EXPR_LOCATION (t),
> > -  op0,
> > -  RECUR (TREE_OPERAND (t, 1)),
> > +   tree op0 = RECUR (TREE_OPERAND (t, 0));
> > +   tree op1 = tsubst_expr (TREE_OPERAND (t, 1), args,
> > +   complain|decltype_flag, in_decl);
> > +   RETURN (build_x_compound_expr (EXPR_LOCATION (t), op0, op1,
> >templated_operator_saved_lookups (t),
> >complain|decltype_flag));
> 
> Hmm, passing decltype_flag to both op1 and the , is concerning.  Can you add a
> test with overloaded operator, where the RHS is a class with a destructor?

I'm not sure if this is what you had in mind, but indeed with this patch
we reject the following with an error outside the immediate context:

struct B { ~B() = delete; };
template B f();

void operator,(int, const B&);

template decltype(42, f()) g(int) = delete; // #1
template void g(...); // #2

int main() {
  g(0); // should select #2
}

gcc/testsuite/g++.dg/cpp0x/decltype-call8.C: In substitution of ‘template decltype ((42, f())) g(int) [with T = B]’:
gcc/testsuite/g++.dg/cpp0x/decltype-call8.C:12:7:   required from here
   12 |   g(0);
  |   ^~~
gcc/testsuite/g++.dg/cpp0x/decltype-call8.C:8:30: error: use of deleted 
function ‘B::~B()’
8 | template decltype(42, f()) g(int) = delete; // #1
  |~~^~~~
gcc/testsuite/g++.dg/cpp0x/decltype-call8.C:3:12: note: declared here
3 | struct B { ~B() = delete; };
  |^

Ultimately because unary_complex_lvalue isn't SFINAE-enabled.  If we
fix that with the following then we accept the testcase as before.

diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc
index 9d4d95f85bf..58c45542793 100644
--- a/gcc/cp/class.cc
+++ b/gcc/cp/class.cc
@@ -556,7 +556,7 @@ build_simple_base_path (tree expr, tree binfo)
 into `(*(a ?   : )).x', and so on.  A COND_EXPR is only
 an lvalue in the front end; only _DECLs and _REFs are lvalues
 in the back end.  */
-  temp = unary_complex_lvalue (ADDR_EXPR, expr);
+  temp = unary_complex_lvalue (ADDR_EXPR, expr, tf_warning_or_error);
   if (temp)
expr = cp_build_fold_indirect_ref (temp);
 
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 1fa710d7154..d826afcdb5c 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -8130,7 +8130,7 @@ extern tree cp_build_addr_expr(tree, 
tsubst_flags_t);
 extern tree cp_build_unary_op   (enum tree_code, tree, bool,
  tsubst_flags_t);
 extern tree genericize_compound_lvalue (tree);
-extern tree unary_complex_lvalue   (enum tree_code, tree);
+extern tree unary_complex_lvalue   (enum tree_code, tree, 
tsubst_flags_t);
 extern tree build_x_conditional_expr   (location_t, tree, tree, tree,
  tsubst_flags_t);
 extern tree build_x_compound_expr_from_list(tree, expr_list_kind,
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 4f2cb2cd402

Re: [PATCH] c++: non-dependent .* folding [PR112427]

2023-11-10 Thread Patrick Palka
On Fri, 10 Nov 2023, Patrick Palka wrote:

> On Thu, 9 Nov 2023, Jason Merrill wrote:
> 
> > On 11/8/23 16:59, Patrick Palka wrote:
> > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > > trunk?
> > > 
> > > -- >8 --
> > > 
> > > Here when building up the non-dependent .* expression, we crash from
> > > fold_convert on 'b.a' due to this (templated) COMPONENT_REF having an
> > > IDENTIFIER_NODE instead of FIELD_DECL operand that middle-end routines
> > > expect.  Like in r14-4899-gd80a26cca02587, this patch fixes this by
> > > replacing the problematic piecemeal folding with a single call to
> > > cp_fully_fold.
> > > 
> > >   PR c++/112427
> > > 
> > > gcc/cp/ChangeLog:
> > > 
> > >   * typeck2.cc (build_m_component_ref): Use cp_convert, build2 and
> > >   cp_fully_fold instead of fold_build_pointer_plus and fold_convert.
> > 
> > > gcc/testsuite/ChangeLog:
> > > 
> > >   * g++.dg/template/non-dependent29.C: New test.
> > > ---
> > >   gcc/cp/typeck2.cc   |  5 -
> > >   gcc/testsuite/g++.dg/template/non-dependent29.C | 13 +
> > >   2 files changed, 17 insertions(+), 1 deletion(-)
> > >   create mode 100644 gcc/testsuite/g++.dg/template/non-dependent29.C
> > > 
> > > diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc
> > > index 309903afed8..208004221da 100644
> > > --- a/gcc/cp/typeck2.cc
> > > +++ b/gcc/cp/typeck2.cc
> > > @@ -2378,7 +2378,10 @@ build_m_component_ref (tree datum, tree component,
> > > tsubst_flags_t complain)
> > > /* Build an expression for "object + offset" where offset is the
> > >value stored in the pointer-to-data-member.  */
> > > ptype = build_pointer_type (type);
> > > -  datum = fold_build_pointer_plus (fold_convert (ptype, datum),
> > > component);
> > > +  datum = cp_convert (ptype, datum, complain);
> > > +  datum = build2 (POINTER_PLUS_EXPR, ptype,
> > > +   datum, convert_to_ptrofftype (component));
> > 
> > We shouldn't need to build the POINTER_PLUS_EXPR at all in template context.
> > OK with that change.
> 
> Hmm, that seems harmless at first glance, but I noticed
> build_min_non_dep (called from build_x_binary_op in this case) is
> careful to propagate TREE_SIDE_EFFECTS of the given tree, and so eliding
> POINTER_PLUS_EXPR here could potentially mean that the tree we
> ultimately return from build_x_binary_op when in a template context has
> TREE_SIDE_EFFECTS not set when it used to.  Shall we still elide the
> POINTER_PLUS_EXPR in a template context despite this?
> 
> (The TREE_SIDE_EFFECTS propagation in build_min_non_dep was added in
> r71108 to avoid bogus ahead of time -Wunused-value warnings.  But then
> r105273 later made us stop issuing -Wunused-value warnings ahead of time
> altogether.  So perhaps we don't need to maintain the TREE_SIDE_EFFECTS
> flag on templated trees at all anymore?)

IMO it'd be nice to restore ahead of time -Wunused-value warnings;
it seems the original motivation for r105273 / PR8057 was to avoid
redundantly issuing a warning twice, once ahead of time and once at
instantiation time, which we now could do in a better way with
warning_suppressed_p etc.  If so, then IIUC eliding the POINTER_PLUS_EXPR
could mean we'd incorrectly issue a -Wunused-value warning for e.g.
'a.*f()' in a template context?

> 
> > 
> > Jason
> > 
> > 
> 



Re: [PATCH] c++: non-dependent .* folding [PR112427]

2023-11-10 Thread Patrick Palka
On Thu, 9 Nov 2023, Jason Merrill wrote:

> On 11/8/23 16:59, Patrick Palka wrote:
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > trunk?
> > 
> > -- >8 --
> > 
> > Here when building up the non-dependent .* expression, we crash from
> > fold_convert on 'b.a' due to this (templated) COMPONENT_REF having an
> > IDENTIFIER_NODE instead of FIELD_DECL operand that middle-end routines
> > expect.  Like in r14-4899-gd80a26cca02587, this patch fixes this by
> > replacing the problematic piecemeal folding with a single call to
> > cp_fully_fold.
> > 
> > PR c++/112427
> > 
> > gcc/cp/ChangeLog:
> > 
> > * typeck2.cc (build_m_component_ref): Use cp_convert, build2 and
> > cp_fully_fold instead of fold_build_pointer_plus and fold_convert.
> 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/template/non-dependent29.C: New test.
> > ---
> >   gcc/cp/typeck2.cc   |  5 -
> >   gcc/testsuite/g++.dg/template/non-dependent29.C | 13 +
> >   2 files changed, 17 insertions(+), 1 deletion(-)
> >   create mode 100644 gcc/testsuite/g++.dg/template/non-dependent29.C
> > 
> > diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc
> > index 309903afed8..208004221da 100644
> > --- a/gcc/cp/typeck2.cc
> > +++ b/gcc/cp/typeck2.cc
> > @@ -2378,7 +2378,10 @@ build_m_component_ref (tree datum, tree component,
> > tsubst_flags_t complain)
> > /* Build an expression for "object + offset" where offset is the
> >  value stored in the pointer-to-data-member.  */
> > ptype = build_pointer_type (type);
> > -  datum = fold_build_pointer_plus (fold_convert (ptype, datum),
> > component);
> > +  datum = cp_convert (ptype, datum, complain);
> > +  datum = build2 (POINTER_PLUS_EXPR, ptype,
> > + datum, convert_to_ptrofftype (component));
> 
> We shouldn't need to build the POINTER_PLUS_EXPR at all in template context.
> OK with that change.

Hmm, that seems harmless at first glance, but I noticed
build_min_non_dep (called from build_x_binary_op in this case) is
careful to propagate TREE_SIDE_EFFECTS of the given tree, and so eliding
POINTER_PLUS_EXPR here could potentially mean that the tree we
ultimately return from build_x_binary_op when in a template context has
TREE_SIDE_EFFECTS not set when it used to.  Shall we still elide the
POINTER_PLUS_EXPR in a template context despite this?

(The TREE_SIDE_EFFECTS propagation in build_min_non_dep was added in
r71108 to avoid bogus ahead of time -Wunused-value warnings.  But then
r105273 later made us stop issuing -Wunused-value warnings ahead of time
altogether.  So perhaps we don't need to maintain the TREE_SIDE_EFFECTS
flag on templated trees at all anymore?)

> 
> Jason
> 
> 



Re: [PATCH] c++: constantness of local var in constexpr fn [PR111703, PR112269]

2023-11-10 Thread Patrick Palka
On Wed, 1 Nov 2023, Patrick Palka wrote:

> On Tue, 31 Oct 2023, Patrick Palka wrote:
> 
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > trunk?  Does it look OK for release branches as well for sake of PR111703?

Ping.

> > 
> > -- >8 --
> > 
> > potential_constant_expression was incorrectly treating most local
> > variables from a constexpr function as (potentially) constant because it
> > wasn't considering the 'now' parameter.  This patch fixes this by
> > relaxing some var_in_maybe_constexpr_fn checks accordingly, which turns
> > out to partially fix two recently reported regressions:
> > 
> > PR111703 is a regression caused by r11-550-gf65a3299a521a4 for
> > restricting constexpr evaluation during warning-dependent folding.
> > The mechanism is intended to restrict only constant evaluation of the
> > instantiated non-dependent expression, but it also ends up restricting
> > constant evaluation (as part of satisfaction) during instantiation of
> > the expression, in particular when resolving the ck_rvalue conversion of
> > the 'x' argument into a copy constructor call.
> 
> Oops, this analysis is inaccurate for this specific testcase (although
> the general idea is the same)...  We don't call fold_for_warn on 'f(x)'
> but rather on its 'x' argument that has been processed by
> convert_arguments into an IMPLICIT_CONV_EXPR.  And it's the
> instantiation of this IMPLICIT_CONV_EXPR that turns it into a copy
> constructor call.  There is no ck_rvalue conversion at all here since
> 'f' is a function pointer, not an actual function, and so ICSes don't
> get computed (IIUC).  If 'f' is changed to be an actual function then
> there's no issue since build_over_call doesn't perform argument
> conversions when in a template context and therefore doesn't call
> check_function_arguments on the converted arguments (from which the
> problematic fold_for_warn call occurs).
> 
> > This seems like a bug in
> > the mechanism[1], though I don't know if we want to refine the mechanism
> > or get rid of it completely since the original testcases which motivated
> > the mechanism are fixed more simply by r13-1225-gb00b95198e6720.  In any
> > case, this patch partially fixes this by making us correctly treat 'x'
> > and therefore 'f(x)' in the below testcase as non-constant, which
> > prevents the problematic warning-dependent folding from occurring at
> > all.  If this bug crops up again then I figure we could decide what to
> > do with the mechanism then.
> > 
> > PR112269 is caused by r14-4796-g3e3d73ed5e85e7 for merging tsubst_copy
> > into tsubst_copy_and_build.  tsubst_copy used to exit early when 'args'
> > was empty, behavior which that commit deliberately didn't preserve.
> > This early exit masked the fact that COMPLEX_EXPR wasn't handled by
> > tsubst at all, and is a tree code that apparently we could see during
> > warning-dependent folding on some targets.  A complete fix is to add
> > handling for this tree code in tsubst_expr, but this patch should fix
> > the reported testsuite failures since the situations where COMPLEX_EXPR
> > crops up in  turn out to not be constant expressions in the
> > first place after this patch.

N.B. adding COMPLEX_EXPR handling to tsubst_expr is complicated by the
fact that these COMPLEX_EXRRs are created by convert_to_complex (a
middle-end routine) which occasionally creates SAVE_EXPR sub trees which
we don't expect to see inside templated trees...

> > 
> > [1]: The mechanism incorrectly assumes that instantiation of the
> > non-dependent expression shouldn't induce any template instantiation
> > since ahead of time checking of the expression should've already induced
> > whatever template instantiation was needed, but in this case although
> > overload resolution was performed ahead of time, a ck_rvalue conversion
> > gets resolved to a copy constructor call only at instantiation time.
> > 
> > PR c++/111703
> > 
> > gcc/cp/ChangeLog:
> > 
> > * constexpr.cc (potential_constant_expression_1) :
> > Only consider var_in_maybe_constexpr_fn if 'now' is false.
> > : Likewise.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/cpp2a/concepts-fn8.C: New test.
> > ---
> >  gcc/cp/constexpr.cc   |  4 ++--
> >  gcc/testsuite/g++.dg/cpp2a/concepts-fn8.C | 24 +++
> >  2 files changed, 26 insertions(+), 2 deletions(-)
> >  create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-fn8.C
> > 
> > diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> &

[PATCH] libstdc++: Fix forwarding in __take/drop_of_repeat_view [PR112453]

2023-11-09 Thread Patrick Palka
Tested on x86_64-pc-linux-gnu, does this look OK for trunk/13?  (The
&& overloads are also missing on earlier branches, but I don't think
it makes a difference there since all uses of that operator* are on
lvalues before this fix.)

-- >8 --

We need to respect the value category of the repeat_view passed to these
two functions when accessing its _M_value member.  This revealed that
the space-efficient partial specialization of __box lacks && overloads
of operator* to match std::optional's API.

PR libstdc++/112453

libstdc++-v3/ChangeLog:

* include/std/ranges (__detail::__box::operator*): Define &&
overloads as well.
(__detail::__take_of_repeat_view): Forward __r when accessing
its _M_value member.
(__detail::__drop_of_repeat_view): Likewise.
* testsuite/std/ranges/repeat/1.cc (test07): New test.
---
 libstdc++-v3/include/std/ranges   | 20 ++-
 libstdc++-v3/testsuite/std/ranges/repeat/1.cc | 13 
 2 files changed, 28 insertions(+), 5 deletions(-)

diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 7893e3a84c9..41f95dc8f78 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -250,13 +250,21 @@ namespace ranges
{ return true; };
 
constexpr _Tp&
-   operator*() noexcept
+   operator*() & noexcept
{ return _M_value; }
 
constexpr const _Tp&
-   operator*() const noexcept
+   operator*() const & noexcept
{ return _M_value; }
 
+   constexpr _Tp&&
+   operator*() && noexcept
+   { return std::move(_M_value); }
+
+   constexpr const _Tp&&
+   operator*() const && noexcept
+   { return std::move(_M_value); }
+
constexpr _Tp*
operator->() noexcept
{ return std::__addressof(_M_value); }
@@ -7799,9 +7807,10 @@ namespace views::__adaptor
  using _Tp = remove_cvref_t<_Range>;
  static_assert(__is_repeat_view<_Tp>);
  if constexpr (sized_range<_Tp>)
-   return views::repeat(*__r._M_value, std::min(ranges::distance(__r), 
__n));
+   return views::repeat(*std::forward<_Range>(__r)._M_value,
+std::min(ranges::distance(__r), __n));
  else
-   return views::repeat(*__r._M_value, __n);
+   return views::repeat(*std::forward<_Range>(__r)._M_value, __n);
}
 
   template
@@ -7813,7 +7822,8 @@ namespace views::__adaptor
  if constexpr (sized_range<_Tp>)
{
  auto __sz = ranges::distance(__r);
- return views::repeat(*__r._M_value, __sz - std::min(__sz, __n));
+ return views::repeat(*std::forward<_Range>(__r)._M_value,
+  __sz - std::min(__sz, __n));
}
  else
return __r;
diff --git a/libstdc++-v3/testsuite/std/ranges/repeat/1.cc 
b/libstdc++-v3/testsuite/std/ranges/repeat/1.cc
index 30636407ee2..9551414e2c8 100644
--- a/libstdc++-v3/testsuite/std/ranges/repeat/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/repeat/1.cc
@@ -2,6 +2,7 @@
 
 #include 
 #include 
+#include 
 #include 
 
 #if __cpp_lib_ranges_repeat != 202207L
@@ -137,6 +138,17 @@ test06()
   static_assert( requires { views::repeat(move_only{}, 2); } );
 }
 
+void
+test07()
+{
+  // PR libstdc++/112453
+  auto t = std::views::repeat(std::make_unique(5)) | std::views::take(2);
+  auto d = std::views::repeat(std::make_unique(5)) | std::views::drop(2);
+
+  auto t2 = std::views::repeat(std::make_unique(5), 4) | 
std::views::take(2);
+  auto d2 = std::views::repeat(std::make_unique(5), 4) | 
std::views::drop(2);
+}
+
 int
 main()
 {
@@ -146,4 +158,5 @@ main()
   static_assert(test04());
   test05();
   test06();
+  test07();
 }
-- 
2.43.0.rc1



[PATCH] c++: non-dependent .* folding [PR112427]

2023-11-08 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?

-- >8 --

Here when building up the non-dependent .* expression, we crash from
fold_convert on 'b.a' due to this (templated) COMPONENT_REF having an
IDENTIFIER_NODE instead of FIELD_DECL operand that middle-end routines
expect.  Like in r14-4899-gd80a26cca02587, this patch fixes this by
replacing the problematic piecemeal folding with a single call to
cp_fully_fold.

PR c++/112427

gcc/cp/ChangeLog:

* typeck2.cc (build_m_component_ref): Use cp_convert, build2 and
cp_fully_fold instead of fold_build_pointer_plus and fold_convert.

gcc/testsuite/ChangeLog:

* g++.dg/template/non-dependent29.C: New test.
---
 gcc/cp/typeck2.cc   |  5 -
 gcc/testsuite/g++.dg/template/non-dependent29.C | 13 +
 2 files changed, 17 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/template/non-dependent29.C

diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc
index 309903afed8..208004221da 100644
--- a/gcc/cp/typeck2.cc
+++ b/gcc/cp/typeck2.cc
@@ -2378,7 +2378,10 @@ build_m_component_ref (tree datum, tree component, 
tsubst_flags_t complain)
   /* Build an expression for "object + offset" where offset is the
 value stored in the pointer-to-data-member.  */
   ptype = build_pointer_type (type);
-  datum = fold_build_pointer_plus (fold_convert (ptype, datum), component);
+  datum = cp_convert (ptype, datum, complain);
+  datum = build2 (POINTER_PLUS_EXPR, ptype,
+ datum, convert_to_ptrofftype (component));
+  datum = cp_fully_fold (datum);
   datum = cp_build_fold_indirect_ref (datum);
   if (datum == error_mark_node)
return error_mark_node;
diff --git a/gcc/testsuite/g++.dg/template/non-dependent29.C 
b/gcc/testsuite/g++.dg/template/non-dependent29.C
new file mode 100644
index 000..41bd11ae6b4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/non-dependent29.C
@@ -0,0 +1,13 @@
+// PR c++/112427
+
+struct A { int m; void f(); };
+struct B { A a; };
+
+template
+void f(B b) {
+  int A::*pd = ::m;
+  b.a.*pd;
+
+  void (A::*pf)() = ::f;
+  (b.a.*pf)();
+}
-- 
2.43.0.rc1



Re: [PATCH] c++: decltype of (by-value captured reference) [PR79620]

2023-11-07 Thread Patrick Palka
On Tue, 7 Nov 2023, Patrick Palka wrote:

> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> OK for trunk?
> 
> -- >8 --
> 
> The capture decltype handling in finish_decltype_type wasn't looking
> through implicit INDIRECT_REF (added by convert_from_reference), which
> caused us to incorrectly resolve decltype((x)) to float& below.

Oops, this should say decltype((r)).  We already correctly resolve
decltype((x)) to const float& (since x isn't a reference).

> 
> We still don't fully accept the example ultimately because when
> processing the decltype inside the first lambda's trailing return type,
> we're in lambda type scope but not yet in lambda function scope that
> the check looks for, which seems like an orthogonal bug.
> 
>   PR c++/79620
> 
> gcc/cp/ChangeLog:
> 
>   * cp-tree.h (STRIP_REFERENCE_REF): Define.
>   * semantics.cc (finish_decltype_type): Use it to look
>   through implicit INDIRECT_REF when deciding whether to
>   call capture_decltype.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp0x/lambda/lambda-decltype3.C: New test.
> ---
>  gcc/cp/cp-tree.h  |  4 +++
>  gcc/cp/semantics.cc   |  4 +--
>  .../g++.dg/cpp0x/lambda/lambda-decltype3.C| 28 +++
>  3 files changed, 34 insertions(+), 2 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-decltype3.C
> 
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index b2603d4830e..1fa710d7154 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -4084,6 +4084,10 @@ struct GTY(()) lang_decl {
> && TREE_TYPE (TREE_OPERAND (NODE, 0)) \
> && TYPE_REF_P (TREE_TYPE (TREE_OPERAND ((NODE), 0
>  
> +/* Look through an implicit INDIRECT_REF from convert_from_reference.  */
> +#define STRIP_REFERENCE_REF(NODE)\
> +  (REFERENCE_REF_P (NODE) ? TREE_OPERAND (NODE, 0) : NODE)
> +
>  /* True iff this represents an lvalue being treated as an rvalue during 
> return
> or throw as per [class.copy.elision].  */
>  #define IMPLICIT_RVALUE_P(NODE) \
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index f583dedd6cf..8df4521bf7c 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -11717,10 +11717,10 @@ finish_decltype_type (tree expr, bool 
> id_expression_or_member_access_p,
>transformed into an access to a corresponding data member
>of the closure type that would have been declared if x
>were a use of the denoted entity.  */
> -  if (outer_automatic_var_p (expr)
> +  if (outer_automatic_var_p (STRIP_REFERENCE_REF (expr))
> && current_function_decl
> && LAMBDA_FUNCTION_P (current_function_decl))
> - type = capture_decltype (expr);
> + type = capture_decltype (STRIP_REFERENCE_REF (expr));
>else if (error_operand_p (expr))
>   type = error_mark_node;
>else if (expr == current_class_ptr)
> diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-decltype3.C 
> b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-decltype3.C
> new file mode 100644
> index 000..7fc157aefb5
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-decltype3.C
> @@ -0,0 +1,28 @@
> +// PR c++/79620
> +// [expr.prim.id.unqual] example 1
> +// { dg-do compile { target c++11 } }
> +
> +void f() {
> +  float x,  = x;
> +
> +  [=]() -> decltype((x)) {  // lambda returns float const& because this 
> lambda is not mutable and
> +// x is an lvalue
> +decltype(x) y1; // y1 has type float
> +decltype((x)) y2 = y1;  // y2 has type float const&
> +decltype(r) r1 = y1;// r1 has type float&
> +decltype((r)) r2 = y2;  // r2 has type float const&
> +return y2;  // { dg-bogus "'float&' to 'const float'" "" 
> { xfail *-*-* } }
> +  };
> +
> +  [=](decltype((x)) y) {
> +decltype((x)) z = x;// OK, y has type float&, z has type float 
> const&
> +  };
> +
> +  [=] {
> +[](decltype((x)) y) {}; // OK, lambda takes a parameter of type 
> float const&
> +
> +[x=1](decltype((x)) y) {
> +  decltype((x)) z = x;  // OK, y has type int&, z has type int const&
> +};
> +  };
> +}
> -- 
> 2.43.0.rc0.23.g8be77c5de6
> 
> 



[PATCH] c++: decltype of (by-value captured reference) [PR79620]

2023-11-07 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
OK for trunk?

-- >8 --

The capture decltype handling in finish_decltype_type wasn't looking
through implicit INDIRECT_REF (added by convert_from_reference), which
caused us to incorrectly resolve decltype((x)) to float& below.

We still don't fully accept the example ultimately because when
processing the decltype inside the first lambda's trailing return type,
we're in lambda type scope but not yet in lambda function scope that
the check looks for, which seems like an orthogonal bug.

PR c++/79620

gcc/cp/ChangeLog:

* cp-tree.h (STRIP_REFERENCE_REF): Define.
* semantics.cc (finish_decltype_type): Use it to look
through implicit INDIRECT_REF when deciding whether to
call capture_decltype.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/lambda/lambda-decltype3.C: New test.
---
 gcc/cp/cp-tree.h  |  4 +++
 gcc/cp/semantics.cc   |  4 +--
 .../g++.dg/cpp0x/lambda/lambda-decltype3.C| 28 +++
 3 files changed, 34 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-decltype3.C

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index b2603d4830e..1fa710d7154 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4084,6 +4084,10 @@ struct GTY(()) lang_decl {
&& TREE_TYPE (TREE_OPERAND (NODE, 0))   \
&& TYPE_REF_P (TREE_TYPE (TREE_OPERAND ((NODE), 0
 
+/* Look through an implicit INDIRECT_REF from convert_from_reference.  */
+#define STRIP_REFERENCE_REF(NODE)  \
+  (REFERENCE_REF_P (NODE) ? TREE_OPERAND (NODE, 0) : NODE)
+
 /* True iff this represents an lvalue being treated as an rvalue during return
or throw as per [class.copy.elision].  */
 #define IMPLICIT_RVALUE_P(NODE) \
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index f583dedd6cf..8df4521bf7c 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -11717,10 +11717,10 @@ finish_decltype_type (tree expr, bool 
id_expression_or_member_access_p,
 transformed into an access to a corresponding data member
 of the closure type that would have been declared if x
 were a use of the denoted entity.  */
-  if (outer_automatic_var_p (expr)
+  if (outer_automatic_var_p (STRIP_REFERENCE_REF (expr))
  && current_function_decl
  && LAMBDA_FUNCTION_P (current_function_decl))
-   type = capture_decltype (expr);
+   type = capture_decltype (STRIP_REFERENCE_REF (expr));
   else if (error_operand_p (expr))
type = error_mark_node;
   else if (expr == current_class_ptr)
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-decltype3.C 
b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-decltype3.C
new file mode 100644
index 000..7fc157aefb5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-decltype3.C
@@ -0,0 +1,28 @@
+// PR c++/79620
+// [expr.prim.id.unqual] example 1
+// { dg-do compile { target c++11 } }
+
+void f() {
+  float x,  = x;
+
+  [=]() -> decltype((x)) {  // lambda returns float const& because this 
lambda is not mutable and
+// x is an lvalue
+decltype(x) y1; // y1 has type float
+decltype((x)) y2 = y1;  // y2 has type float const&
+decltype(r) r1 = y1;// r1 has type float&
+decltype((r)) r2 = y2;  // r2 has type float const&
+return y2;  // { dg-bogus "'float&' to 'const float'" "" { 
xfail *-*-* } }
+  };
+
+  [=](decltype((x)) y) {
+decltype((x)) z = x;// OK, y has type float&, z has type float 
const&
+  };
+
+  [=] {
+[](decltype((x)) y) {}; // OK, lambda takes a parameter of type float 
const&
+
+[x=1](decltype((x)) y) {
+  decltype((x)) z = x;  // OK, y has type int&, z has type int const&
+};
+  };
+}
-- 
2.43.0.rc0.23.g8be77c5de6



[PATCH] c++: decltype of capture proxy [PR79378, PR96917]

2023-11-07 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?

-- >8 --

We usually don't see capture proxies in finish_decltype_type because
process_outer_var_ref is a no-op inside an unevaluated context and
so a use of a capture inside decltype refers directly to the captured
variable.  But we can still see a capture proxy during decltype(auto)
deduction and for decltype of an init-capture, which suggests we need
to handle capture proxies specially within finish_decltype_type (since
they're always implicitly const).  This patch adds such handling.

PR c++/79378
PR c++/96917

gcc/cp/ChangeLog:

* semantics.cc (finish_decltype_type): Handle an id-expression
naming a capture proxy specially.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1y/decltype-auto7.C: New test.
* g++.dg/cpp1y/lambda-init20.C: New test.
---
 gcc/cp/semantics.cc | 28 +--
 gcc/testsuite/g++.dg/cpp1y/decltype-auto7.C | 53 +
 gcc/testsuite/g++.dg/cpp1y/lambda-init20.C  | 22 +
 3 files changed, 98 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/decltype-auto7.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-init20.C

diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 4059e74bdb7..f583dedd6cf 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -11643,12 +11643,30 @@ finish_decltype_type (tree expr, bool 
id_expression_or_member_access_p,
   /* Fall through for fields that aren't bitfields.  */
  gcc_fallthrough ();
 
-case FUNCTION_DECL:
 case VAR_DECL:
-case CONST_DECL:
-case PARM_DECL:
-case RESULT_DECL:
-case TEMPLATE_PARM_INDEX:
+ if (is_capture_proxy (expr))
+   {
+ if (is_normal_capture_proxy (expr))
+   {
+ expr = DECL_CAPTURED_VARIABLE (expr);
+ type = TREE_TYPE (expr);
+ type = non_reference (type);
+   }
+ else
+   {
+ expr = DECL_VALUE_EXPR (expr);
+ gcc_assert (TREE_CODE (expr) == COMPONENT_REF);
+ expr = TREE_OPERAND (expr, 1);
+ type = TREE_TYPE (expr);
+   }
+ break;
+   }
+ /* Fall through.  */
+   case FUNCTION_DECL:
+   case CONST_DECL:
+   case PARM_DECL:
+   case RESULT_DECL:
+   case TEMPLATE_PARM_INDEX:
  expr = mark_type_use (expr);
   type = TREE_TYPE (expr);
  if (VAR_P (expr) && DECL_NTTP_OBJECT_P (expr))
diff --git a/gcc/testsuite/g++.dg/cpp1y/decltype-auto7.C 
b/gcc/testsuite/g++.dg/cpp1y/decltype-auto7.C
new file mode 100644
index 000..a37b9db38d4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/decltype-auto7.C
@@ -0,0 +1,53 @@
+// PR c++/96917
+// { dg-do compile { target c++14 } }
+
+int main() {
+  int x = 0;
+  int y = 0;
+  const int cx = 0;
+  const int cy = 0;
+
+  [x, , cx, ] {
+decltype(auto) a = x;
+using ty1 = int;
+using ty1 = decltype(x);
+using ty1 = decltype(a);
+
+decltype(auto) b = y;
+using ty2 = int;
+using ty2 = decltype(y);
+using ty2 = decltype(b);
+
+decltype(auto) ca = cx;
+using ty3 = const int;
+using ty3 = decltype(cx);
+using ty3 = decltype(ca);
+
+decltype(auto) cb = cy;
+using ty4 = const int;
+using ty4 = decltype(cy);
+using ty4 = decltype(cb);
+  };
+
+  [x=x, =y, cx=cx, =cy] {
+decltype(auto) a = x;
+using ty1 = int;
+using ty1 = decltype(x);
+using ty1 = decltype(a);
+
+decltype(auto) b = y;
+using ty2 = int&;
+using ty2 = decltype(y);
+using ty2 = decltype(b);
+
+decltype(auto) ca = cx;
+using ty3 = int;
+using ty3 = decltype(cx);
+using ty3 = decltype(ca);
+
+decltype(auto) cb = cy;
+using ty4 = const int&;
+using ty4 = decltype(cy);
+using ty4 = decltype(cb);
+  };
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-init20.C 
b/gcc/testsuite/g++.dg/cpp1y/lambda-init20.C
new file mode 100644
index 000..a06b77a664d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-init20.C
@@ -0,0 +1,22 @@
+// PR c++/79378
+// { dg-do compile { target c++14 } }
+
+int main() {
+  int x = 0;
+  [x=x, =x] {
+using ty1 = int;
+using ty1 = decltype(x);
+
+using ty2 = int&;
+using ty2 = decltype(r);
+  };
+
+  const int cx = 0;
+  [x=cx, =cx] {
+using ty1 = int;
+using ty1 = decltype(x);
+
+using ty2 = const int&;
+using ty2 = decltype(r);
+  };
+}
-- 
2.43.0.rc0.23.g8be77c5de6



[PATCH] c++: fix tf_decltype manipulation for COMPOUND_EXPR

2023-11-07 Thread Patrick Palka
bootstrapped and regtested on x86_64-pc-linxu-gnu, does this look OK for trunk?

-- >8 --

In the COMPOUND_EXPR case of tsubst_expr, we were redundantly clearing
the tf_decltype flag when substituting the LHS and also neglecting to
propagate it when substituting the RHS.  This patch corrects this flag
manipulation, which allows us to accept the below testcase.

gcc/cp/ChangeLog:

* pt.cc (tsubst_expr) : Don't redundantly
clear tf_decltype when substituting the LHS.  Propagate
tf_decltype when substituting the RHS.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/decltype-call7.C: New test.
---
 gcc/cp/pt.cc| 9 -
 gcc/testsuite/g++.dg/cpp0x/decltype-call7.C | 9 +
 2 files changed, 13 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/decltype-call7.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 521749df525..5f879287a58 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -20382,11 +20382,10 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
 
 case COMPOUND_EXPR:
   {
-   tree op0 = tsubst_expr (TREE_OPERAND (t, 0), args,
-   complain & ~tf_decltype, in_decl);
-   RETURN (build_x_compound_expr (EXPR_LOCATION (t),
-  op0,
-  RECUR (TREE_OPERAND (t, 1)),
+   tree op0 = RECUR (TREE_OPERAND (t, 0));
+   tree op1 = tsubst_expr (TREE_OPERAND (t, 1), args,
+   complain|decltype_flag, in_decl);
+   RETURN (build_x_compound_expr (EXPR_LOCATION (t), op0, op1,
   templated_operator_saved_lookups (t),
   complain|decltype_flag));
   }
diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype-call7.C 
b/gcc/testsuite/g++.dg/cpp0x/decltype-call7.C
new file mode 100644
index 000..4ce3e68381e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/decltype-call7.C
@@ -0,0 +1,9 @@
+// { dg-do compile { target c++11 } }
+
+struct A;
+template A f();
+
+template
+decltype(42, f()) g();
+
+using type = decltype(g());
-- 
2.43.0.rc0.23.g8be77c5de6



Re: Remove redundant partial specialization in _Nth_type

2023-11-03 Thread Patrick Palka
yn Sat, 28 Oct 2023, Feng Jisen wrote:

> This patch remove a redundant partial specialization in class _Nth_type.
> For the original metafunction _Nth_type code,
>   # 0
>   template     struct _Nth_type<0, _Tp0, 
> _Rest...>
>     { using type = _Tp0; };
>  # 1
>   template
>     struct _Nth_type<0, _Tp0, _Tp1, _Rest...>
>     { using type = _Tp0; };   # 2
>   template
>     struct _Nth_type<0, _Tp0, _Tp1, _Tp2, _Rest...>
>     { using type = _Tp0; };
>   # 3
>   template typename... _Rest>
> #if __cpp_concepts
>     requires (_Np >= 3)
> #endif
>     struct _Nth_type<_Np, _Tp0, _Tp1, _Tp2, _Rest...>
>     : _Nth_type<_Np - 3, _Rest...>
>     { };
> 
> we need partial specialization # 2 to deal with template argument <0, Tp0, 
> Tp1, Tp2, ...>.
> Because without concepts, both # 0 and # 3 is legal and there is no partial 
> order relationship between them. 
> However, # 1 is redundant. For template argument <0, Tp0, Tp1>, #0 is 
> instantiated and that's enough.

Thanks for the patch!  This looks good to me.

> 
> libstdc++-v3/ChangeLog:
> 
>   * include/bits/utility.h:(_Nth_type) Remove redundant partial 
> specialization.
> 
> 
> diff --git a/libstdc++-v3/include/bits/utility.h 
> b/libstdc++-v3/include/bits/utility.hindex bed94525642..8766dfbc15f 100644
> --- a/libstdc++-v3/include/bits/utility.h
> +++ b/libstdc++-v3/include/bits/utility.h
> @@ -258,10 +258,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>      { };
>  
>  #if ! __cpp_concepts // Need additional specializations to avoid ambiguities.
> -  template
> -    struct _Nth_type<0, _Tp0, _Tp1, _Rest...>
> -    { using type = _Tp0; };
> -
>    template
>      struct _Nth_type<0, _Tp0, _Tp1, _Tp2, _Rest...>
>      { using type = _Tp0; };
> -- 
> 
> 
> 

Re: [PATCH] c++: partial spec constraint checking context [PR105220]

2023-11-03 Thread Patrick Palka
On Tue, 3 May 2022, Jason Merrill wrote:

> On 5/2/22 14:50, Patrick Palka wrote:
> > Currently when checking the constraints of a class template, we do so in
> > the context of the template, not the specialized type.  This is the best
> > we can do for a primary template since the specialized type is valid
> > only if the primary template's constraints are satisfied.
> 
> Hmm, that's unfortunate.  It ought to be possible, if awkward, to form the
> type long enough to check its constraints.

(Sorry, lost track of this patch...)

Seems doable, but I'm not sure if would make any difference in practice?

If the access context during satisfaction of a primary class template's
constraints is the specialization rather than the primary template,
then that should only make a difference if there's some friend declaration
naming the specialization.  But that'd mean the specialization's
constraints had to have been satisfied at that point, before the friend
declaration went into effect.  So either the constraints don't depend on
the access granted by the friend declaration anyway, or they do and the
program is ill-formed (due to either satifaction failure or instability) IIUC.

For example, I don't think an adapted version of the testcase without a
partial specialization is valid, regardless of whether the access context
during satisfaction of A is A or just A:

template
concept fooable = requires(T t) { t.foo(); };

template
struct A { };

struct B {
private:
  friend struct A; // satisfaction failure at this point
  void foo();
};

template struct A;


> 
> > But for a
> > partial specialization, we can assume the specialized type is valid (as
> > a consequence of constraints being checked only when necessary), so we
> > arguably should check the constraints on a partial specialization more
> > specifically in the context of the specialized type, not the template.
> > 
> > This patch implements this by substituting and setting the access
> > context appropriately in satisfy_declaration_constraints.  Note that
> > setting the access context in this case is somewhat redundant since the
> > relevant caller most_specialized_partial_spec will already have set the
> > access context to the specialiation, but this redundancy should be harmless.
> > 
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > trunk and perhaps 12.2 (after the branch is thawed)?
> > 
> > PR c++/105220
> > 
> > gcc/cp/ChangeLog:
> > 
> > * constraint.cc (satisfy_declaration_constraints): When checking
> > the constraints of a partial template specialization, do so in
> > the context of the specialized type not the template.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/cpp2a/concepts-partial-spec12.C: New test.
> > ---
> >   gcc/cp/constraint.cc  | 17 ++---
> >   .../g++.dg/cpp2a/concepts-partial-spec12.C| 19 +++
> >   2 files changed, 33 insertions(+), 3 deletions(-)
> >   create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec12.C
> > 
> > diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> > index 94f6222b436..772f8532b47 100644
> > --- a/gcc/cp/constraint.cc
> > +++ b/gcc/cp/constraint.cc
> > @@ -3253,11 +3253,22 @@ satisfy_declaration_constraints (tree t, tree args,
> > sat_info info)
> >   {
> > if (!push_tinst_level (t, args))
> > return result;
> > -  tree pattern = DECL_TEMPLATE_RESULT (t);
> > +  tree ascope = DECL_TEMPLATE_RESULT (t);
> > +  if (CLASS_TYPE_P (TREE_TYPE (t))
> > + && CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (t)))
> > +   {
> > + gcc_checking_assert (t == most_general_template (t));
> > + /* When checking the constraints on a partial specialization,
> > +do so in the context of the specialized type, not the template.
> > +This substitution should always succeed since we shouldn't
> > +be checking constraints thereof unless the specialized type
> > +is valid.  */
> > + ascope = tsubst (ascope, args, tf_none, info.in_decl);
> > +   }
> > push_to_top_level ();
> > -  push_access_scope (pattern);
> > +  push_access_scope (ascope);
> > result = satisfy_normalized_constraints (norm, args, info);
> > -  pop_access_scope (pattern);
> > +  pop_access_scope (ascope);
> > pop_from_top_level ();
> > pop_tinst_level ();
> >   }
> > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec12.C
> > b/gcc/t

Re: [PATCH] c++: constantness of local var in constexpr fn [PR111703, PR112269]

2023-11-01 Thread Patrick Palka
On Tue, 31 Oct 2023, Patrick Palka wrote:

> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk?  Does it look OK for release branches as well for sake of PR111703?
> 
> -- >8 --
> 
> potential_constant_expression was incorrectly treating most local
> variables from a constexpr function as (potentially) constant because it
> wasn't considering the 'now' parameter.  This patch fixes this by
> relaxing some var_in_maybe_constexpr_fn checks accordingly, which turns
> out to partially fix two recently reported regressions:
> 
> PR111703 is a regression caused by r11-550-gf65a3299a521a4 for
> restricting constexpr evaluation during warning-dependent folding.
> The mechanism is intended to restrict only constant evaluation of the
> instantiated non-dependent expression, but it also ends up restricting
> constant evaluation (as part of satisfaction) during instantiation of
> the expression, in particular when resolving the ck_rvalue conversion of
> the 'x' argument into a copy constructor call.

Oops, this analysis is inaccurate for this specific testcase (although
the general idea is the same)...  We don't call fold_for_warn on 'f(x)'
but rather on its 'x' argument that has been processed by
convert_arguments into an IMPLICIT_CONV_EXPR.  And it's the
instantiation of this IMPLICIT_CONV_EXPR that turns it into a copy
constructor call.  There is no ck_rvalue conversion at all here since
'f' is a function pointer, not an actual function, and so ICSes don't
get computed (IIUC).  If 'f' is changed to be an actual function then
there's no issue since build_over_call doesn't perform argument
conversions when in a template context and therefore doesn't call
check_function_arguments on the converted arguments (from which the
problematic fold_for_warn call occurs).

> This seems like a bug in
> the mechanism[1], though I don't know if we want to refine the mechanism
> or get rid of it completely since the original testcases which motivated
> the mechanism are fixed more simply by r13-1225-gb00b95198e6720.  In any
> case, this patch partially fixes this by making us correctly treat 'x'
> and therefore 'f(x)' in the below testcase as non-constant, which
> prevents the problematic warning-dependent folding from occurring at
> all.  If this bug crops up again then I figure we could decide what to
> do with the mechanism then.
> 
> PR112269 is caused by r14-4796-g3e3d73ed5e85e7 for merging tsubst_copy
> into tsubst_copy_and_build.  tsubst_copy used to exit early when 'args'
> was empty, behavior which that commit deliberately didn't preserve.
> This early exit masked the fact that COMPLEX_EXPR wasn't handled by
> tsubst at all, and is a tree code that apparently we could see during
> warning-dependent folding on some targets.  A complete fix is to add
> handling for this tree code in tsubst_expr, but this patch should fix
> the reported testsuite failures since the situations where COMPLEX_EXPR
> crops up in  turn out to not be constant expressions in the
> first place after this patch.
> 
> [1]: The mechanism incorrectly assumes that instantiation of the
> non-dependent expression shouldn't induce any template instantiation
> since ahead of time checking of the expression should've already induced
> whatever template instantiation was needed, but in this case although
> overload resolution was performed ahead of time, a ck_rvalue conversion
> gets resolved to a copy constructor call only at instantiation time.
> 
>   PR c++/111703
> 
> gcc/cp/ChangeLog:
> 
>   * constexpr.cc (potential_constant_expression_1) :
>   Only consider var_in_maybe_constexpr_fn if 'now' is false.
>   : Likewise.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp2a/concepts-fn8.C: New test.
> ---
>  gcc/cp/constexpr.cc   |  4 ++--
>  gcc/testsuite/g++.dg/cpp2a/concepts-fn8.C | 24 +++
>  2 files changed, 26 insertions(+), 2 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-fn8.C
> 
> diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> index c05760e6789..8a6b210144a 100644
> --- a/gcc/cp/constexpr.cc
> +++ b/gcc/cp/constexpr.cc
> @@ -9623,7 +9623,7 @@ potential_constant_expression_1 (tree t, bool 
> want_rval, bool strict, bool now,
> return RECUR (DECL_VALUE_EXPR (t), rval);
>   }
>if (want_rval
> -   && !var_in_maybe_constexpr_fn (t)
> +   && (now || !var_in_maybe_constexpr_fn (t))
> && !type_dependent_expression_p (t)
> && !decl_maybe_constant_var_p (t)
> && (strict
> @@ -9737,7 +9737,7 @@ potential_constant_expression_1 (tree t, bool 
> want_rval, bool strict, bool now,
>  STRIP_NOPS (x);
>

[PATCH] c++: constantness of local var in constexpr fn [PR111703, PR112269]

2023-10-31 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?  Does it look OK for release branches as well for sake of PR111703?

-- >8 --

potential_constant_expression was incorrectly treating most local
variables from a constexpr function as (potentially) constant because it
wasn't considering the 'now' parameter.  This patch fixes this by
relaxing some var_in_maybe_constexpr_fn checks accordingly, which turns
out to partially fix two recently reported regressions:

PR111703 is a regression caused by r11-550-gf65a3299a521a4 for
restricting constexpr evaluation during warning-dependent folding.
The mechanism is intended to restrict only constant evaluation of the
instantiated non-dependent expression, but it also ends up restricting
constant evaluation (as part of satisfaction) during instantiation of
the expression, in particular when resolving the ck_rvalue conversion of
the 'x' argument into a copy constructor call.  This seems like a bug in
the mechanism[1], though I don't know if we want to refine the mechanism
or get rid of it completely since the original testcases which motivated
the mechanism are fixed more simply by r13-1225-gb00b95198e6720.  In any
case, this patch partially fixes this by making us correctly treat 'x'
and therefore 'f(x)' in the below testcase as non-constant, which
prevents the problematic warning-dependent folding from occurring at
all.  If this bug crops up again then I figure we could decide what to
do with the mechanism then.

PR112269 is caused by r14-4796-g3e3d73ed5e85e7 for merging tsubst_copy
into tsubst_copy_and_build.  tsubst_copy used to exit early when 'args'
was empty, behavior which that commit deliberately didn't preserve.
This early exit masked the fact that COMPLEX_EXPR wasn't handled by
tsubst at all, and is a tree code that apparently we could see during
warning-dependent folding on some targets.  A complete fix is to add
handling for this tree code in tsubst_expr, but this patch should fix
the reported testsuite failures since the situations where COMPLEX_EXPR
crops up in  turn out to not be constant expressions in the
first place after this patch.

[1]: The mechanism incorrectly assumes that instantiation of the
non-dependent expression shouldn't induce any template instantiation
since ahead of time checking of the expression should've already induced
whatever template instantiation was needed, but in this case although
overload resolution was performed ahead of time, a ck_rvalue conversion
gets resolved to a copy constructor call only at instantiation time.

PR c++/111703

gcc/cp/ChangeLog:

* constexpr.cc (potential_constant_expression_1) :
Only consider var_in_maybe_constexpr_fn if 'now' is false.
: Likewise.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts-fn8.C: New test.
---
 gcc/cp/constexpr.cc   |  4 ++--
 gcc/testsuite/g++.dg/cpp2a/concepts-fn8.C | 24 +++
 2 files changed, 26 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-fn8.C

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index c05760e6789..8a6b210144a 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -9623,7 +9623,7 @@ potential_constant_expression_1 (tree t, bool want_rval, 
bool strict, bool now,
  return RECUR (DECL_VALUE_EXPR (t), rval);
}
   if (want_rval
- && !var_in_maybe_constexpr_fn (t)
+ && (now || !var_in_maybe_constexpr_fn (t))
  && !type_dependent_expression_p (t)
  && !decl_maybe_constant_var_p (t)
  && (strict
@@ -9737,7 +9737,7 @@ potential_constant_expression_1 (tree t, bool want_rval, 
bool strict, bool now,
 STRIP_NOPS (x);
 if (is_this_parameter (x) && !is_capture_proxy (x))
  {
-   if (!var_in_maybe_constexpr_fn (x))
+   if (now || !var_in_maybe_constexpr_fn (x))
  {
if (flags & tf_error)
  constexpr_error (loc, fundef_p, "use of % in a "
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-fn8.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-fn8.C
new file mode 100644
index 000..3f63a5b28d7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-fn8.C
@@ -0,0 +1,24 @@
+// PR c++/111703
+// { dg-do compile { target c++20 } }
+
+template
+constexpr bool always_true() { return true; }
+
+struct P {
+  P() = default;
+
+  template
+requires (always_true()) // { dg-bogus "used before its definition" }
+  constexpr P(const T&) { }
+
+  int n, m;
+};
+
+void (*f)(P);
+
+template
+constexpr bool g() {
+  P x;
+  f(x); // { dg-bogus "from here" }
+  return true;
+}
-- 
2.42.0.526.g3130c155df



Re: [PATCH v3 3/3] c++: note other candidates when diagnosing deletedness

2023-10-27 Thread Patrick Palka
On Fri, 27 Oct 2023, Patrick Palka wrote:

> On Fri, 27 Oct 2023, Jason Merrill wrote:
> 
> > On 10/27/23 15:55, Patrick Palka wrote:
> > > With the previous two patches in place, we can now extend our
> > > deletedness diagnostic to note the other considered candidates, e.g.:
> > > 
> > >deleted16.C: In function 'int main()':
> > >deleted16.C:10:4: error: use of deleted function 'void f(int)'
> > >   10 |   f(0);
> > >  |   ~^~~
> > >deleted16.C:5:6: note: declared here
> > >5 | void f(int) = delete;
> > >  |  ^
> > >deleted16.C:5:6: note: candidate: 'void f(int)' (deleted)
> > >deleted16.C:6:6: note: candidate: 'void f(...)'
> > >6 | void f(...);
> > >  |  ^
> > >deleted16.C:7:6: note: candidate: 'void f(int, int)'
> > >7 | void f(int, int);
> > >  |  ^
> > >deleted16.C:7:6: note:   candidate expects 2 arguments, 1 provided
> > > 
> > > These notes are controlled by a new command line flag -fnote-all-cands,
> > > which also controls whether we note ignored candidates more generally.
> > > 
> > > gcc/ChangeLog:
> > > 
> > >   * doc/invoke.texi (C++ Dialect Options): Document -fnote-all-cands.

It just occurred to me that this despite this flag being C++ specific, it
probably should be documented under "Diagnostic Message Formatting Options",
like -fdiagnostics-show-template-tree is.

> > > 
> > > gcc/c-family/ChangeLog:
> > > 
> > >   * c.opt: Add -fnote-all-cands.
> > > 
> > > gcc/cp/ChangeLog:
> > > 
> > >   * call.cc (print_z_candidates): Only print ignored candidates
> > >   when -fnote-all-cands is set.
> > >   (build_over_call): When diagnosing deletedness, call
> > >   print_z_candidates if -fnote-all-cands is set.
> > 
> > My suggestion was also to suggest using the flag in cases where it would 
> > make
> > a difference, e.g.
> > 
> > note: some candidates omitted, use '-fnote-all-cands' to display them
> 
> Ah thanks, fixed.  That'll help a lot with discoverability of the flag.
> 
> > 
> > Maybe "-fdiagnostics-all-candidates"?
> 
> Nice, that's a better name indeed :)
> 
> How does the following look?  Full bootstrap/regtest in progress.
> 
> Here's the output of e.g. deleted16a.C.  I think I'd prefer to not print
> the source line when emitting the suggestion, but I don't know how to do
> that properly (aside from e.g. emitting the note at UNKNOWN_LOCATION).
> 
> In file included from gcc/testsuite/g++.dg/cpp0x/deleted16a.C:4:
> gcc/testsuite/g++.dg/cpp0x/deleted16.C: In function ‘int main()’:
> gcc/testsuite/g++.dg/cpp0x/deleted16.C:21:4: error: use of deleted function 
> ‘void f(int)’
>21 |   f(0); // { dg-error "deleted" }
>   |   ~^~~
> gcc/testsuite/g++.dg/cpp0x/deleted16.C:6:6: note: declared here
> 6 | void f(int) = delete; // { dg-message "declared here" }
>   |  ^
> gcc/testsuite/g++.dg/cpp0x/deleted16.C:21:4: note: use 
> ‘-fdiagnostics-all-candidates’ to display considered candidates
>21 |   f(0); // { dg-error "deleted" }
>   |   ~^~~
> gcc/testsuite/g++.dg/cpp0x/deleted16.C:22:4: error: use of deleted function 
> ‘void g(int)’
>22 |   g(0); // { dg-error "deleted" }
>   |   ~^~~
> gcc/testsuite/g++.dg/cpp0x/deleted16.C:12:6: note: declared here
>12 | void g(int) = delete; // { dg-message "declared here" }
>   |  ^
> gcc/testsuite/g++.dg/cpp0x/deleted16.C:22:4: note: use 
> ‘-fdiagnostics-all-candidates’ to display considered candidates
>22 |   g(0); // { dg-error "deleted" }
>   |   ~^~~
> gcc/testsuite/g++.dg/cpp0x/deleted16.C:23:4: error: use of deleted function 
> ‘void h(T, T) [with T = int]’
>23 |   h(1, 1); // { dg-error "deleted" }
>   |   ~^~
> gcc/testsuite/g++.dg/cpp0x/deleted16.C:17:24: note: declared here
>17 | template void h(T, T) = delete; // { dg-message "declared 
> here|candidate" }
>   |^
> gcc/testsuite/g++.dg/cpp0x/deleted16.C:23:4: note: use 
> ‘-fdiagnostics-all-candidates’ to display considered candidates
>23 |   h(1, 1); // { dg-error "deleted" }
>   |   ~^~
> 
> -- >8 --
> 
> 
> Subject: [PATCH 3/3] c++: note other candidates when diagnosing deletedness
> 
> With the previous two patches in place, we can now extend our
> deletedness diagnostic to note the other considered candidates, e.g.:
> 

Re: [PATCH v3 3/3] c++: note other candidates when diagnosing deletedness

2023-10-27 Thread Patrick Palka
On Fri, 27 Oct 2023, Jason Merrill wrote:

> On 10/27/23 15:55, Patrick Palka wrote:
> > With the previous two patches in place, we can now extend our
> > deletedness diagnostic to note the other considered candidates, e.g.:
> > 
> >deleted16.C: In function 'int main()':
> >deleted16.C:10:4: error: use of deleted function 'void f(int)'
> >   10 |   f(0);
> >  |   ~^~~
> >deleted16.C:5:6: note: declared here
> >5 | void f(int) = delete;
> >  |  ^
> >deleted16.C:5:6: note: candidate: 'void f(int)' (deleted)
> >deleted16.C:6:6: note: candidate: 'void f(...)'
> >6 | void f(...);
> >  |  ^
> >deleted16.C:7:6: note: candidate: 'void f(int, int)'
> >7 | void f(int, int);
> >  |  ^
> >deleted16.C:7:6: note:   candidate expects 2 arguments, 1 provided
> > 
> > These notes are controlled by a new command line flag -fnote-all-cands,
> > which also controls whether we note ignored candidates more generally.
> > 
> > gcc/ChangeLog:
> > 
> > * doc/invoke.texi (C++ Dialect Options): Document -fnote-all-cands.
> > 
> > gcc/c-family/ChangeLog:
> > 
> > * c.opt: Add -fnote-all-cands.
> > 
> > gcc/cp/ChangeLog:
> > 
> > * call.cc (print_z_candidates): Only print ignored candidates
> > when -fnote-all-cands is set.
> > (build_over_call): When diagnosing deletedness, call
> > print_z_candidates if -fnote-all-cands is set.
> 
> My suggestion was also to suggest using the flag in cases where it would make
> a difference, e.g.
> 
> note: some candidates omitted, use '-fnote-all-cands' to display them

Ah thanks, fixed.  That'll help a lot with discoverability of the flag.

> 
> Maybe "-fdiagnostics-all-candidates"?

Nice, that's a better name indeed :)

How does the following look?  Full bootstrap/regtest in progress.

Here's the output of e.g. deleted16a.C.  I think I'd prefer to not print
the source line when emitting the suggestion, but I don't know how to do
that properly (aside from e.g. emitting the note at UNKNOWN_LOCATION).

In file included from gcc/testsuite/g++.dg/cpp0x/deleted16a.C:4:
gcc/testsuite/g++.dg/cpp0x/deleted16.C: In function ‘int main()’:
gcc/testsuite/g++.dg/cpp0x/deleted16.C:21:4: error: use of deleted function 
‘void f(int)’
   21 |   f(0); // { dg-error "deleted" }
  |   ~^~~
gcc/testsuite/g++.dg/cpp0x/deleted16.C:6:6: note: declared here
6 | void f(int) = delete; // { dg-message "declared here" }
  |  ^
gcc/testsuite/g++.dg/cpp0x/deleted16.C:21:4: note: use 
‘-fdiagnostics-all-candidates’ to display considered candidates
   21 |   f(0); // { dg-error "deleted" }
  |   ~^~~
gcc/testsuite/g++.dg/cpp0x/deleted16.C:22:4: error: use of deleted function 
‘void g(int)’
   22 |   g(0); // { dg-error "deleted" }
  |   ~^~~
gcc/testsuite/g++.dg/cpp0x/deleted16.C:12:6: note: declared here
   12 | void g(int) = delete; // { dg-message "declared here" }
  |  ^
gcc/testsuite/g++.dg/cpp0x/deleted16.C:22:4: note: use 
‘-fdiagnostics-all-candidates’ to display considered candidates
   22 |   g(0); // { dg-error "deleted" }
  |   ~^~~
gcc/testsuite/g++.dg/cpp0x/deleted16.C:23:4: error: use of deleted function 
‘void h(T, T) [with T = int]’
   23 |   h(1, 1); // { dg-error "deleted" }
  |   ~^~
gcc/testsuite/g++.dg/cpp0x/deleted16.C:17:24: note: declared here
   17 | template void h(T, T) = delete; // { dg-message "declared 
here|candidate" }
  |^
gcc/testsuite/g++.dg/cpp0x/deleted16.C:23:4: note: use 
‘-fdiagnostics-all-candidates’ to display considered candidates
   23 |   h(1, 1); // { dg-error "deleted" }
  |   ~^~

-- >8 --


Subject: [PATCH 3/3] c++: note other candidates when diagnosing deletedness

With the previous two patches in place, we can now extend our
deletedness diagnostic to note the other considered candidates, e.g.:

  deleted16.C: In function 'int main()':
  deleted16.C:10:4: error: use of deleted function 'void f(int)'
 10 |   f(0);
|   ~^~~
  deleted16.C:5:6: note: declared here
  5 | void f(int) = delete;
|  ^
  deleted16.C:5:6: note: candidate: 'void f(int)' (deleted)
  deleted16.C:6:6: note: candidate: 'void f(...)'
  6 | void f(...);
|  ^
  deleted16.C:7:6: note: candidate: 'void f(int, int)'
  7 | void f(int, int);
|  ^
  deleted16.C:7:6: note:   candidate expects 2 arguments, 1 provided

These notes are controlled by a new command line flag
-fdiagnostics-all-candidates which also controls whether we note
ignored candidates more generally.

gcc/ChangeLog:

* doc/invoke.texi (C++ Dialec

Re: [pushed] c++: fix tourney logic

2023-10-27 Thread Patrick Palka
On Fri, 27 Oct 2023, Patrick Palka wrote:

> On Fri, 27 Oct 2023, Patrick Palka wrote:
> 
> > On Fri, 20 Oct 2023, Jason Merrill wrote:
> > 
> > > Tested x86_64-pc-linux-gnu, applying to trunk.  Patrick, sorry I didn't 
> > > apply
> > > this sooner.
> > > 
> > > -- 8< --
> > > 
> > > In r13-3766 I changed the logic at the end of tourney to avoid redundant
> > > comparisons, but the change also meant skipping any less-good matches
> > > between the champ_compared_to_predecessor candidate and champ itself.
> > > 
> > > This should not be a correctness issue, since we believe that joust is a
> > > partial order.  But it can lead to missed warnings, as in this testcase.
> > 
> > I suppose this rules out optimizing tourney via transitivity when in
> > a non-SFINAE context since it'd cause missed warnings such as these.
> > But maybe we'd still want to optimize the second pass via transitivity
> > in a SFINAE context?
> 
> Eh, maybe it's not worth it either way..  According to some quick
> experiments, making the second pass in tourney assume transitivity by
> going up to the most recent tie even in non-SFINAE contexts reduces the
> total number of non-trivial calls to tourney by about 5%.  Doing the

total number of non-trivial calls to joust, rather

> same in only SFINAE contexts reduces the number of calls by less than 1%.
> 
> > 
> > > 
> > > gcc/cp/ChangeLog:
> > > 
> > >   * call.cc (tourney): Only skip champ_compared_to_predecessor.
> > > 
> > > gcc/testsuite/ChangeLog:
> > > 
> > >   * g++.dg/warn/Wsign-promo1.C: New test.
> > > ---
> > >  gcc/cp/call.cc   |  5 +++--
> > >  gcc/testsuite/g++.dg/warn/Wsign-promo1.C | 15 +++
> > >  2 files changed, 18 insertions(+), 2 deletions(-)
> > >  create mode 100644 gcc/testsuite/g++.dg/warn/Wsign-promo1.C
> > > 
> > > diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
> > > index 657eca93d23..a49fde949d5 100644
> > > --- a/gcc/cp/call.cc
> > > +++ b/gcc/cp/call.cc
> > > @@ -13227,10 +13227,11 @@ tourney (struct z_candidate *candidates, 
> > > tsubst_flags_t complain)
> > >   been compared to.  */
> > >  
> > >for (challenger = candidates;
> > > -   challenger != champ
> > > -  && challenger != champ_compared_to_predecessor;
> > > +   challenger != champ;
> > > challenger = challenger->next)
> > >  {
> > > +  if (challenger == champ_compared_to_predecessor)
> > > + continue;
> > >fate = joust (champ, challenger, 0, complain);
> > >if (fate != 1)
> > >   return NULL;
> > > diff --git a/gcc/testsuite/g++.dg/warn/Wsign-promo1.C 
> > > b/gcc/testsuite/g++.dg/warn/Wsign-promo1.C
> > > new file mode 100644
> > > index 000..51b76eee735
> > > --- /dev/null
> > > +++ b/gcc/testsuite/g++.dg/warn/Wsign-promo1.C
> > > @@ -0,0 +1,15 @@
> > > +// Check that we get joust warnings from comparing the final champ to a
> > > +// candidate between it and the previous champ.
> > > +
> > > +// { dg-additional-options -Wsign-promo }
> > > +
> > > +struct A { A(int); };
> > > +
> > > +enum E { e };
> > > +
> > > +int f(int, A);
> > > +int f(unsigned, A);
> > > +int f(int, int);
> > > +
> > > +int i = f(e, 42);// { dg-warning "passing 'E'" }
> > > +// { dg-warning "in call to 'int f" "" { target *-*-* } .-1 }
> > > 
> > > base-commit: 084addf8a700fab9222d4127ab8524920d0ca481
> > > -- 
> > > 2.39.3
> > > 
> > > 
> > 
> 



Re: [pushed] c++: fix tourney logic

2023-10-27 Thread Patrick Palka
On Fri, 27 Oct 2023, Patrick Palka wrote:

> On Fri, 20 Oct 2023, Jason Merrill wrote:
> 
> > Tested x86_64-pc-linux-gnu, applying to trunk.  Patrick, sorry I didn't 
> > apply
> > this sooner.
> > 
> > -- 8< --
> > 
> > In r13-3766 I changed the logic at the end of tourney to avoid redundant
> > comparisons, but the change also meant skipping any less-good matches
> > between the champ_compared_to_predecessor candidate and champ itself.
> > 
> > This should not be a correctness issue, since we believe that joust is a
> > partial order.  But it can lead to missed warnings, as in this testcase.
> 
> I suppose this rules out optimizing tourney via transitivity when in
> a non-SFINAE context since it'd cause missed warnings such as these.
> But maybe we'd still want to optimize the second pass via transitivity
> in a SFINAE context?

Eh, maybe it's not worth it either way..  According to some quick
experiments, making the second pass in tourney assume transitivity by
going up to the most recent tie even in non-SFINAE contexts reduces the
total number of non-trivial calls to tourney by about 5%.  Doing the
same in only SFINAE contexts reduces the number of calls by less than 1%.

> 
> > 
> > gcc/cp/ChangeLog:
> > 
> > * call.cc (tourney): Only skip champ_compared_to_predecessor.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/warn/Wsign-promo1.C: New test.
> > ---
> >  gcc/cp/call.cc   |  5 +++--
> >  gcc/testsuite/g++.dg/warn/Wsign-promo1.C | 15 +++
> >  2 files changed, 18 insertions(+), 2 deletions(-)
> >  create mode 100644 gcc/testsuite/g++.dg/warn/Wsign-promo1.C
> > 
> > diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
> > index 657eca93d23..a49fde949d5 100644
> > --- a/gcc/cp/call.cc
> > +++ b/gcc/cp/call.cc
> > @@ -13227,10 +13227,11 @@ tourney (struct z_candidate *candidates, 
> > tsubst_flags_t complain)
> >   been compared to.  */
> >  
> >for (challenger = candidates;
> > -   challenger != champ
> > -&& challenger != champ_compared_to_predecessor;
> > +   challenger != champ;
> > challenger = challenger->next)
> >  {
> > +  if (challenger == champ_compared_to_predecessor)
> > +   continue;
> >fate = joust (champ, challenger, 0, complain);
> >if (fate != 1)
> > return NULL;
> > diff --git a/gcc/testsuite/g++.dg/warn/Wsign-promo1.C 
> > b/gcc/testsuite/g++.dg/warn/Wsign-promo1.C
> > new file mode 100644
> > index 000..51b76eee735
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/warn/Wsign-promo1.C
> > @@ -0,0 +1,15 @@
> > +// Check that we get joust warnings from comparing the final champ to a
> > +// candidate between it and the previous champ.
> > +
> > +// { dg-additional-options -Wsign-promo }
> > +
> > +struct A { A(int); };
> > +
> > +enum E { e };
> > +
> > +int f(int, A);
> > +int f(unsigned, A);
> > +int f(int, int);
> > +
> > +int i = f(e, 42);  // { dg-warning "passing 'E'" }
> > +// { dg-warning "in call to 'int f" "" { target *-*-* } .-1 }
> > 
> > base-commit: 084addf8a700fab9222d4127ab8524920d0ca481
> > -- 
> > 2.39.3
> > 
> > 
> 



Re: [pushed] c++: fix tourney logic

2023-10-27 Thread Patrick Palka
On Fri, 20 Oct 2023, Jason Merrill wrote:

> Tested x86_64-pc-linux-gnu, applying to trunk.  Patrick, sorry I didn't apply
> this sooner.
> 
> -- 8< --
> 
> In r13-3766 I changed the logic at the end of tourney to avoid redundant
> comparisons, but the change also meant skipping any less-good matches
> between the champ_compared_to_predecessor candidate and champ itself.
> 
> This should not be a correctness issue, since we believe that joust is a
> partial order.  But it can lead to missed warnings, as in this testcase.

I suppose this rules out optimizing tourney via transitivity when in
a non-SFINAE context since it'd cause missed warnings such as these.
But maybe we'd still want to optimize the second pass via transitivity
in a SFINAE context?

> 
> gcc/cp/ChangeLog:
> 
>   * call.cc (tourney): Only skip champ_compared_to_predecessor.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/warn/Wsign-promo1.C: New test.
> ---
>  gcc/cp/call.cc   |  5 +++--
>  gcc/testsuite/g++.dg/warn/Wsign-promo1.C | 15 +++
>  2 files changed, 18 insertions(+), 2 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/warn/Wsign-promo1.C
> 
> diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
> index 657eca93d23..a49fde949d5 100644
> --- a/gcc/cp/call.cc
> +++ b/gcc/cp/call.cc
> @@ -13227,10 +13227,11 @@ tourney (struct z_candidate *candidates, 
> tsubst_flags_t complain)
>   been compared to.  */
>  
>for (challenger = candidates;
> -   challenger != champ
> -  && challenger != champ_compared_to_predecessor;
> +   challenger != champ;
> challenger = challenger->next)
>  {
> +  if (challenger == champ_compared_to_predecessor)
> + continue;
>fate = joust (champ, challenger, 0, complain);
>if (fate != 1)
>   return NULL;
> diff --git a/gcc/testsuite/g++.dg/warn/Wsign-promo1.C 
> b/gcc/testsuite/g++.dg/warn/Wsign-promo1.C
> new file mode 100644
> index 000..51b76eee735
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/warn/Wsign-promo1.C
> @@ -0,0 +1,15 @@
> +// Check that we get joust warnings from comparing the final champ to a
> +// candidate between it and the previous champ.
> +
> +// { dg-additional-options -Wsign-promo }
> +
> +struct A { A(int); };
> +
> +enum E { e };
> +
> +int f(int, A);
> +int f(unsigned, A);
> +int f(int, int);
> +
> +int i = f(e, 42);// { dg-warning "passing 'E'" }
> +// { dg-warning "in call to 'int f" "" { target *-*-* } .-1 }
> 
> base-commit: 084addf8a700fab9222d4127ab8524920d0ca481
> -- 
> 2.39.3
> 
> 



[PATCH v3 1/3] c++: sort candidates according to viability

2023-10-27 Thread Patrick Palka
New in patch 1/3:
  * consistently use "non-viable" instead of "unviable"
throughout
  * make 'champ' and 'challenger' in 'tourney' be z_candidate**
to simplify moving 'champ' to the front of the list.  drive-by
cleanups in tourney, including renaming 'champ_compared_to_predecessor'
to 'previous_worse_champ' for clarity.
New in patch 2/3:
  * consistently use "non-viable" instead of "unviable" throughout
New in patch 3/3:
  * introduce new -fnote-all-cands flag that controls noting other
candidates when diagnosing deletedness, and also controls
noting "ignored" candidates in general.

-- >8 --

This patch:

  * changes splice_viable to move the non-viable candidates to the end
of the list instead of removing them outright
  * makes tourney move the best candidate to the front of the candidate
list
  * adjusts print_z_candidates to preserve our behavior of printing only
viable candidates when diagnosing ambiguity
  * adds a parameter to print_z_candidates to control this default behavior
(the follow-up patch will want to print all candidates when diagnosing
deletedness)

Thus after this patch we have access to the entire candidate list through
the best viable candidate.

This change also happens to fix diagnostics for the below testcase where
we currently neglect to note the third candidate, since the presence of
the two unordered non-strictly viable candidates causes splice_viable to
prematurely get rid of the non-viable third candidate.

gcc/cp/ChangeLog:

* call.cc: Include "tristate.h".
(splice_viable): Sort the candidate list according to viability.
Don't remove non-viable candidates from the list.
(print_z_candidates): Add defaulted only_viable_p parameter.
By default only print non-viable candidates if there is no
viable candidate.
(tourney): Make 'candidates' parameter a reference.  Ignore
non-viable candidates.  Move the true champ to the front
of the candidates list, and update 'candidates' to point to
the front.  Drive-by cleanups, including renaming
'champ_compared_to_predecessor' to 'previous_worse_champ'.

gcc/testsuite/ChangeLog:

* g++.dg/overload/error5.C: New test.
---
 gcc/cp/call.cc | 181 ++---
 gcc/testsuite/g++.dg/overload/error5.C |  12 ++
 2 files changed, 117 insertions(+), 76 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/overload/error5.C

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 2eb54b5b6ed..5d175b93a47 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -43,6 +43,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "attribs.h"
 #include "decl.h"
 #include "gcc-rich-location.h"
+#include "tristate.h"
 
 /* The various kinds of conversion.  */
 
@@ -160,7 +161,7 @@ static struct obstack conversion_obstack;
 static bool conversion_obstack_initialized;
 struct rejection_reason;
 
-static struct z_candidate * tourney (struct z_candidate *, tsubst_flags_t);
+static struct z_candidate * tourney (struct z_candidate *&, tsubst_flags_t);
 static int equal_functions (tree, tree);
 static int joust (struct z_candidate *, struct z_candidate *, bool,
  tsubst_flags_t);
@@ -176,7 +177,8 @@ static void op_error (const op_location_t &, enum 
tree_code, enum tree_code,
 static struct z_candidate *build_user_type_conversion_1 (tree, tree, int,
 tsubst_flags_t);
 static void print_z_candidate (location_t, const char *, struct z_candidate *);
-static void print_z_candidates (location_t, struct z_candidate *);
+static void print_z_candidates (location_t, struct z_candidate *,
+   tristate = tristate::unknown ());
 static tree build_this (tree);
 static struct z_candidate *splice_viable (struct z_candidate *, bool, bool *);
 static bool any_strictly_viable (struct z_candidate *);
@@ -3700,68 +3702,60 @@ add_template_conv_candidate (struct z_candidate 
**candidates, tree tmpl,
 }
 
 /* The CANDS are the set of candidates that were considered for
-   overload resolution.  Return the set of viable candidates, or CANDS
-   if none are viable.  If any of the candidates were viable, set
+   overload resolution.  Sort CANDS so that the strictly viable
+   candidates appear first, followed by non-strictly viable candidates,
+   followed by non-viable candidates.  Returns the first candidate
+   in this sorted list.  If any of the candidates were viable, set
*ANY_VIABLE_P to true.  STRICT_P is true if a candidate should be
-   considered viable only if it is strictly viable.  */
+   considered viable only if it is strictly viable when setting
+   *ANY_VIABLE_P.  */
 
 static struct z_candidate*
 splice_viable (struct z_candidate *cands,
   bool strict_p,
   bool *any_viable_p)
 {
-  struct z_candidate *viable;
-  struct z_candidate **last_viable;
-  struct z_candidate 

[PATCH v3 2/3] c++: remember candidates that we ignored

2023-10-27 Thread Patrick Palka
During overload resolution, we sometimes outright ignore a function in
the overload set and leave no trace of it in the candidates list, for
example when we find a perfect non-template candidate we discard all
function templates, or when the callee is a template-id we discard all
non-template functions.  We should still however make note of these
non-viable functions when diagnosing overload resolution failure, but
that's not possible if they're not present in the returned candidates
list.

To that end, this patch reworks add_candidates to add such ignored
functions to the list.  The new rr_ignored rejection reason is somewhat
of a catch-all; we could perhaps split it up into more specific rejection
reasons, but I leave that as future work.

gcc/cp/ChangeLog:

* call.cc (enum rejection_reason_code): Add rr_ignored.
(add_ignored_candidate): Define.
(ignored_candidate_p): Define.
(add_template_candidate_real): Do add_ignored_candidate
instead of returning NULL.
(splice_viable): Put ignored (non-viable) candidates last.
(print_z_candidate): Handle ignored candidates.
(build_new_function_call): Refine shortcut that calls
cp_build_function_call_vec now that non-templates can
appear in the candidate list for a template-id call.
(add_candidates): Replace 'bad_fns' overload with 'bad_cands'
candidate list.  When not considering a candidate, add it
to the list as an ignored candidate.  Add all 'bad_cands'
to the overload set as well.

gcc/testsuite/ChangeLog:

* g++.dg/diagnostic/param-type-mismatch-2.C: Rename template
function test_7 that accidentally (perhaps) shares the same
name as its non-template callee.
* g++.dg/overload/error6.C: New test.
---
 gcc/cp/call.cc| 150 +-
 .../g++.dg/diagnostic/param-type-mismatch-2.C |  20 +--
 gcc/testsuite/g++.dg/overload/error6.C|   9 ++
 3 files changed, 133 insertions(+), 46 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/overload/error6.C

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 5d175b93a47..81cc029dddb 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -441,7 +441,8 @@ enum rejection_reason_code {
   rr_template_unification,
   rr_invalid_copy,
   rr_inherited_ctor,
-  rr_constraint_failure
+  rr_constraint_failure,
+  rr_ignored,
 };
 
 struct conversion_info {
@@ -2224,6 +2225,35 @@ add_candidate (struct z_candidate **candidates,
   return cand;
 }
 
+/* FN is a function from the overload set that we outright didn't even
+   consider (for some reason); add it to the list as an non-viable "ignored"
+   candidate.  */
+
+static z_candidate *
+add_ignored_candidate (z_candidate **candidates, tree fn)
+{
+  /* No need to dynamically allocate these.  */
+  static const rejection_reason reason_ignored = { rr_ignored, {} };
+
+  struct z_candidate *cand = (struct z_candidate *)
+conversion_obstack_alloc (sizeof (struct z_candidate));
+
+  cand->fn = fn;
+  cand->reason = const_cast (_ignored);
+  cand->next = *candidates;
+  *candidates = cand;
+
+  return cand;
+}
+
+/* True iff CAND is a candidate added by add_ignored_candidate.  */
+
+static bool
+ignored_candidate_p (const z_candidate *cand)
+{
+  return cand->reason && cand->reason->code == rr_ignored;
+}
+
 /* Return the number of remaining arguments in the parameter list
beginning with ARG.  */
 
@@ -3471,7 +3501,7 @@ add_template_candidate_real (struct z_candidate 
**candidates, tree tmpl,
 }
 
   if (len < skip_without_in_chrg)
-return NULL;
+return add_ignored_candidate (candidates, tmpl);
 
   if (DECL_CONSTRUCTOR_P (tmpl) && nargs == 2
   && same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (first_arg),
@@ -3609,7 +3639,7 @@ add_template_candidate_real (struct z_candidate 
**candidates, tree tmpl,
   if (((flags & (LOOKUP_ONLYCONVERTING|LOOKUP_LIST_INIT_CTOR))
== LOOKUP_ONLYCONVERTING)
   && DECL_NONCONVERTING_P (fn))
-return NULL;
+return add_ignored_candidate (candidates, fn);
 
   if (DECL_CONSTRUCTOR_P (fn) && nargs == 2)
 {
@@ -3724,6 +3754,9 @@ splice_viable (struct z_candidate *cands,
   z_candidate *non_viable = nullptr;
   z_candidate **non_viable_tail = _viable;
 
+  z_candidate *non_viable_ignored = nullptr;
+  z_candidate **non_viable_ignored_tail = _viable_ignored;
+
   /* Be strict inside templates, since build_over_call won't actually
  do the conversions to get pedwarns.  */
   if (processing_template_decl)
@@ -3742,6 +3775,7 @@ splice_viable (struct z_candidate *cands,
 its viability.  */
   auto& tail = (cand->viable == 1 ? strictly_viable_tail
: cand->viable == -1 ? non_strictly_viable_tail
+   : ignored_candidate_p (cand) ? non_viable_ignored_tail
: non_viable_tail);
   *tail = cand;
   tail = >next;
@@ -3751,7 +3785,8 @@ splice_viable (struct 

[PATCH v3 3/3] c++: note other candidates when diagnosing deletedness

2023-10-27 Thread Patrick Palka
With the previous two patches in place, we can now extend our
deletedness diagnostic to note the other considered candidates, e.g.:

  deleted16.C: In function 'int main()':
  deleted16.C:10:4: error: use of deleted function 'void f(int)'
 10 |   f(0);
|   ~^~~
  deleted16.C:5:6: note: declared here
  5 | void f(int) = delete;
|  ^
  deleted16.C:5:6: note: candidate: 'void f(int)' (deleted)
  deleted16.C:6:6: note: candidate: 'void f(...)'
  6 | void f(...);
|  ^
  deleted16.C:7:6: note: candidate: 'void f(int, int)'
  7 | void f(int, int);
|  ^
  deleted16.C:7:6: note:   candidate expects 2 arguments, 1 provided

These notes are controlled by a new command line flag -fnote-all-cands,
which also controls whether we note ignored candidates more generally.

gcc/ChangeLog:

* doc/invoke.texi (C++ Dialect Options): Document -fnote-all-cands.

gcc/c-family/ChangeLog:

* c.opt: Add -fnote-all-cands.

gcc/cp/ChangeLog:

* call.cc (print_z_candidates): Only print ignored candidates
when -fnote-all-cands is set.
(build_over_call): When diagnosing deletedness, call
print_z_candidates if -fnote-all-cands is set.

gcc/testsuite/ChangeLog:

* g++.dg/overload/error6.C: Pass -fnote-all-cands.
* g++.dg/cpp0x/deleted16.C: New test.
---
 gcc/c-family/c.opt |  4 
 gcc/cp/call.cc |  8 +++-
 gcc/doc/invoke.texi|  5 +
 gcc/testsuite/g++.dg/cpp0x/deleted16.C | 25 +
 gcc/testsuite/g++.dg/overload/error6.C |  1 +
 5 files changed, 42 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/deleted16.C

diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 44b9c862c14..a76f73cc661 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -2006,6 +2006,10 @@ fnil-receivers
 ObjC ObjC++ Var(flag_nil_receivers) Init(1)
 Assume that receivers of Objective-C messages may be nil.
 
+fnote-all-cands
+C++ ObjC++ Var(flag_note_all_cands)
+Note all candidates during overload resolution failure.
+
 flocal-ivars
 ObjC ObjC++ Var(flag_local_ivars) Init(1)
 Allow access to instance variables as if they were local declarations within 
instance method implementations.
diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 81cc029dddb..7ace0e65096 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -4090,6 +4090,8 @@ print_z_candidates (location_t loc, struct z_candidate 
*candidates,
 {
   if (only_viable_p.is_true () && candidates->viable != 1)
break;
+  if (ignored_candidate_p (candidates) && !flag_note_all_cands)
+   break;
   print_z_candidate (loc, N_("candidate:"), candidates);
 }
 }
@@ -9933,7 +9935,11 @@ build_over_call (struct z_candidate *cand, int flags, 
tsubst_flags_t complain)
   if (DECL_DELETED_FN (fn))
 {
   if (complain & tf_error)
-   mark_used (fn);
+   {
+ mark_used (fn);
+ if (cand->next && flag_note_all_cands)
+   print_z_candidates (input_location, cand, /*only_viable_p=*/false);
+   }
   return error_mark_node;
 }
 
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 5a9284d635c..ac82299416c 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -3479,6 +3479,11 @@ Disable built-in declarations of functions that are not 
mandated by
 ANSI/ISO C@.  These include @code{ffs}, @code{alloca}, @code{_exit},
 @code{index}, @code{bzero}, @code{conjf}, and other related functions.
 
+@opindex fnote-all-cands
+@item -fnote-all-cands
+Permit the C++ front end to note all candidates during overload resolution
+failure, including when a deleted function is selected.
+
 @opindex fnothrow-opt
 @item -fnothrow-opt
 Treat a @code{throw()} exception specification as if it were a
diff --git a/gcc/testsuite/g++.dg/cpp0x/deleted16.C 
b/gcc/testsuite/g++.dg/cpp0x/deleted16.C
new file mode 100644
index 000..506caae76b6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/deleted16.C
@@ -0,0 +1,25 @@
+// Verify -fnote-all-cands causes us to note other candidates when a deleted
+// function is selected by overload resolution.
+// { dg-do compile { target c++11 } }
+// { dg-additional-options "-fnote-all-cands" }
+
+void f(int) = delete; // { dg-message "declared here|candidate" }
+void f(...); // { dg-message "candidate" }
+void f(int, int); // { dg-message "candidate" }
+
+// An example where the perfect candidate optimization causes us
+// to ignore function templates.
+void g(int) = delete; // { dg-message "declared here|candidate" }
+template void g(T); // { dg-message "candidate" }
+
+// An example where we have a strictly viable candidate and
+// an incompletely considered bad candidate.
+template void h(T, T) = delete; // { dg-message "declared 
here|candidate" }
+void h(int*, int) = delete; // { dg-message "candidate" }
+
+int main() {
+  f(0); // { dg-error "deleted" }
+  g(0); // { dg-error 

[pushed] c++: add testcase verifying non-dep new-expr checking

2023-10-27 Thread Patrick Palka
N.B. we currently don't diagnose 'new A(1)' below ultimately because
when in a template context our valid ctor call checking only happens for
type_build_ctor_call types.

-- >8 --

gcc/testsuite/ChangeLog:

* g++.dg/template/new14.C: New test.
---
 gcc/testsuite/g++.dg/template/new14.C | 20 
 1 file changed, 20 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/template/new14.C

diff --git a/gcc/testsuite/g++.dg/template/new14.C 
b/gcc/testsuite/g++.dg/template/new14.C
new file mode 100644
index 000..8c0efe47ae2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/new14.C
@@ -0,0 +1,20 @@
+// Verify we check new-expressions ahead of time.
+
+struct A { };
+struct B { B(int); };
+struct C { void* operator new(__SIZE_TYPE__, int); };
+
+template
+void f() {
+  new A(1); // { dg-error "no match" "" { xfail *-*-* } }
+  new B(1, 2); // { dg-error "no match" }
+  new B; // { dg-error "no match" }
+  new C; // { dg-error "no match" }
+}
+
+
+template
+void g() {
+  new int[__SIZE_MAX__]; // { dg-error "exceeds maximum" }
+  new int[__SIZE_MAX__ / sizeof(int)]; // { dg-error "exceeds maximum" }
+}
-- 
2.42.0.482.g2e8e77cbac



Re: [PATCH] c++: more ahead-of-time -Wparentheses warnings

2023-10-26 Thread Patrick Palka
On Thu, 26 Oct 2023, Patrick Palka wrote:

> On Thu, 26 Oct 2023, Jason Merrill wrote:
> 
> > On 10/25/23 14:55, Patrick Palka wrote:
> > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> > > OK for trunk?
> > > 
> > > -- >8 --
> > > 
> > > Now that we don't have to worry about looking thruogh NON_DEPENDENT_EXPR,
> > > we can easily extend the -Wparentheses warning in convert_for_assignment
> > > to consider (non-dependent) templated assignment operator expressions as
> > > well, like r14-4111-g6e92a6a2a72d3b did in maybe_convert_cond.
> > > 
> > > gcc/cp/ChangeLog:
> > > 
> > >   * cp-tree.h (is_assignment_op_expr_p): Declare.
> > >   * semantics.cc (is_assignment_op_expr_p): Generalize to return
> > >   true for assignment operator expression, not just one that
> > >   have been resolved to an operator overload.
> > >   (maybe_convert_cond): Remove now-redundant checks around
> > >   is_assignment_op_expr_p.
> > >   * typeck.cc (convert_for_assignment): Look through implicit
> > >   INDIRECT_REF in -Wparentheses warning logic, and generalize
> > >   to use is_assignment_op_expr_p.
> > 
> > Do we want to factor out the whole warning logic rather than adjust it in 
> > both
> > places?
> 
> Sounds good, like so?  Bootstrap / regtest in progress.
> 
> -- >8 --
> 
> Subject: [PATCH] c++: more ahead-of-time -Wparentheses warnings
> 
> Now that we don't have to worry about looking through NON_DEPENDENT_EXPR,
> we can easily extend the -Wparentheses warning in convert_for_assignment
> to consider (non-dependent) templated assignment operator expressions as
> well, like r14-4111-g6e92a6a2a72d3b did in maybe_convert_cond.
> 
> gcc/cp/ChangeLog:
> 
>   * cp-tree.h (maybe_warn_unparenthesized_assignment): Declare.
>   * semantics.cc (is_assignment_op_expr_p): Generalize to return
>   true for assignment operator expression, not just one that
>   have been resolved to an operator overload.
>   (maybe_warn_unparenthesized_assignment): Factored out from ...
>   (maybe_convert_cond): ... here.
>   (finish_parenthesized_expr): Also mention
>   maybe_warn_unparenthesized_assignment.
>   * typeck.cc (convert_for_assignment): Replace -Wparentheses
>   warning logic with maybe_warn_unparenthesized_assignment.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/warn/Wparentheses-13.C: Strengthen by expecting that
>   the -Wparentheses warning are issued ahead of time.
>   * g++.dg/warn/Wparentheses-23.C: Likewise.
>   * g++.dg/warn/Wparentheses-32.C: Remove xfails.
> ---
>  gcc/cp/cp-tree.h|  1 +
>  gcc/cp/semantics.cc | 55 ++---
>  gcc/cp/typeck.cc| 13 ++---
>  gcc/testsuite/g++.dg/warn/Wparentheses-13.C |  2 -
>  gcc/testsuite/g++.dg/warn/Wparentheses-23.C |  3 --
>  gcc/testsuite/g++.dg/warn/Wparentheses-32.C |  8 +--
>  6 files changed, 44 insertions(+), 38 deletions(-)
> 
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 30fe716b109..98b29e9cf81 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -7875,6 +7875,7 @@ extern tree lambda_regenerating_args(tree);
>  extern tree most_general_lambda  (tree);
>  extern tree finish_omp_target(location_t, tree, 
> tree, bool);
>  extern void finish_omp_target_clauses(location_t, tree, tree 
> *);
> +extern void maybe_warn_unparenthesized_assignment (tree, tsubst_flags_t);
>  
>  /* in tree.cc */
>  extern int cp_tree_operand_length(const_tree);
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index 72ec72de690..5664da9f4f2 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -840,15 +840,20 @@ finish_goto_stmt (tree destination)
>return add_stmt (build_stmt (input_location, GOTO_EXPR, destination));
>  }
>  
> -/* Returns true if CALL is a (possibly wrapped) CALL_EXPR or AGGR_INIT_EXPR
> -   to operator= () that is written as an operator expression. */
> +/* Returns true if T corresponds to an assignment operator expression.  */
> +
>  static bool
> -is_assignment_op_expr_p (tree call)
> +is_assignment_op_expr_p (tree t)
>  {
> -  if (call == NULL_TREE)
> +  if (t == NULL_TREE)
>  return false;
>  
> -  call = extract_call_expr (call);
> +  if (TREE_CODE (t) == MODIFY_EXPR
> +  || (TREE_CODE (t) == MODOP_EXPR
> +   && TREE_CODE (TREE_OPERAND (t, 1)) == NOP_EXPR))
> +return true;
> +
> +  tr

Re: [PATCH] c++: more ahead-of-time -Wparentheses warnings

2023-10-26 Thread Patrick Palka
On Thu, 26 Oct 2023, Jason Merrill wrote:

> On 10/25/23 14:55, Patrick Palka wrote:
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> > OK for trunk?
> > 
> > -- >8 --
> > 
> > Now that we don't have to worry about looking thruogh NON_DEPENDENT_EXPR,
> > we can easily extend the -Wparentheses warning in convert_for_assignment
> > to consider (non-dependent) templated assignment operator expressions as
> > well, like r14-4111-g6e92a6a2a72d3b did in maybe_convert_cond.
> > 
> > gcc/cp/ChangeLog:
> > 
> > * cp-tree.h (is_assignment_op_expr_p): Declare.
> > * semantics.cc (is_assignment_op_expr_p): Generalize to return
> > true for assignment operator expression, not just one that
> > have been resolved to an operator overload.
> > (maybe_convert_cond): Remove now-redundant checks around
> > is_assignment_op_expr_p.
> > * typeck.cc (convert_for_assignment): Look through implicit
> > INDIRECT_REF in -Wparentheses warning logic, and generalize
> > to use is_assignment_op_expr_p.
> 
> Do we want to factor out the whole warning logic rather than adjust it in both
> places?

Sounds good, like so?  Bootstrap / regtest in progress.

-- >8 --

Subject: [PATCH] c++: more ahead-of-time -Wparentheses warnings

Now that we don't have to worry about looking through NON_DEPENDENT_EXPR,
we can easily extend the -Wparentheses warning in convert_for_assignment
to consider (non-dependent) templated assignment operator expressions as
well, like r14-4111-g6e92a6a2a72d3b did in maybe_convert_cond.

gcc/cp/ChangeLog:

* cp-tree.h (maybe_warn_unparenthesized_assignment): Declare.
* semantics.cc (is_assignment_op_expr_p): Generalize to return
true for assignment operator expression, not just one that
have been resolved to an operator overload.
(maybe_warn_unparenthesized_assignment): Factored out from ...
(maybe_convert_cond): ... here.
(finish_parenthesized_expr): Also mention
maybe_warn_unparenthesized_assignment.
* typeck.cc (convert_for_assignment): Replace -Wparentheses
warning logic with maybe_warn_unparenthesized_assignment.

gcc/testsuite/ChangeLog:

* g++.dg/warn/Wparentheses-13.C: Strengthen by expecting that
the -Wparentheses warning are issued ahead of time.
* g++.dg/warn/Wparentheses-23.C: Likewise.
* g++.dg/warn/Wparentheses-32.C: Remove xfails.
---
 gcc/cp/cp-tree.h|  1 +
 gcc/cp/semantics.cc | 55 ++---
 gcc/cp/typeck.cc| 13 ++---
 gcc/testsuite/g++.dg/warn/Wparentheses-13.C |  2 -
 gcc/testsuite/g++.dg/warn/Wparentheses-23.C |  3 --
 gcc/testsuite/g++.dg/warn/Wparentheses-32.C |  8 +--
 6 files changed, 44 insertions(+), 38 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 30fe716b109..98b29e9cf81 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7875,6 +7875,7 @@ extern tree lambda_regenerating_args  (tree);
 extern tree most_general_lambda(tree);
 extern tree finish_omp_target  (location_t, tree, tree, bool);
 extern void finish_omp_target_clauses  (location_t, tree, tree *);
+extern void maybe_warn_unparenthesized_assignment (tree, tsubst_flags_t);
 
 /* in tree.cc */
 extern int cp_tree_operand_length  (const_tree);
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 72ec72de690..5664da9f4f2 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -840,15 +840,20 @@ finish_goto_stmt (tree destination)
   return add_stmt (build_stmt (input_location, GOTO_EXPR, destination));
 }
 
-/* Returns true if CALL is a (possibly wrapped) CALL_EXPR or AGGR_INIT_EXPR
-   to operator= () that is written as an operator expression. */
+/* Returns true if T corresponds to an assignment operator expression.  */
+
 static bool
-is_assignment_op_expr_p (tree call)
+is_assignment_op_expr_p (tree t)
 {
-  if (call == NULL_TREE)
+  if (t == NULL_TREE)
 return false;
 
-  call = extract_call_expr (call);
+  if (TREE_CODE (t) == MODIFY_EXPR
+  || (TREE_CODE (t) == MODOP_EXPR
+ && TREE_CODE (TREE_OPERAND (t, 1)) == NOP_EXPR))
+return true;
+
+  tree call = extract_call_expr (t);
   if (call == NULL_TREE
   || call == error_mark_node
   || !CALL_EXPR_OPERATOR_SYNTAX (call))
@@ -860,6 +865,28 @@ is_assignment_op_expr_p (tree call)
 && DECL_OVERLOADED_OPERATOR_IS (fndecl, NOP_EXPR);
 }
 
+/* Maybe warn about an unparenthesized 'a = b' (appearing in a boolean
+   context).  */
+
+void
+maybe_warn_unparenthesized_assignment (tree t, tsubst_flags_t complain)
+{
+  t = REFERENCE_REF_P (t) ? TREE_OPERAND (t, 0) : t;
+
+  if ((complain & tf_warning)
+  &&am

Re: [PATCH] c++: simplify build_new_1 when in a template context

2023-10-26 Thread Patrick Palka
On Thu, 26 Oct 2023, Jason Merrill wrote:

> On 10/26/23 14:01, Patrick Palka wrote:
> > Since when in a template context we end up just discarding the result
> > of build_new_1, we don't have to bother with much of the code generation
> > it performs.  This patch makes the function exit early, returning a dummy
> > non-erroneous result, once we've done pretty much all ahead of time checks
> > that we could have.  In passing avoid building up 'outer_nelts_check' in
> > a template context too.
> 
> It seems like this stops checking the calls to the constructor and operator
> delete?

Oops, indeed...  I missed that the removed processing_template_decl hunk
still checks the constructor via build_special_member_call.  Never mind
then, I guess the function doesn't admit any easy simplification after all :(
I'll add a testcase verifying such ahead of time checking of new-exprs.

> 
> Jason
> 
> 



[PATCH] c++: simplify build_new_1 when in a template context

2023-10-26 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
OK for trunk?

-- >8 --

Since when in a template context we end up just discarding the result
of build_new_1, we don't have to bother with much of the code generation
it performs.  This patch makes the function exit early, returning a dummy
non-erroneous result, once we've done pretty much all ahead of time checks
that we could have.  In passing avoid building up 'outer_nelts_check' in
a template context too.

gcc/cp/ChangeLog:

* init.cc (build_new_1): Don't build 'outer_nelts_check' when
in a template context.  Exit early returning void_node when
in a template context.  Simplify the remainder of the function
accordingly.
---
 gcc/cp/init.cc | 36 +++-
 1 file changed, 11 insertions(+), 25 deletions(-)

diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index 6444f0a8518..fab1126ca65 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -3281,7 +3281,7 @@ build_new_1 (vec **placement, tree type, 
tree nelts,
  return error_mark_node;
}
}
-  else
+  else if (!processing_template_decl)
{
  /* When a runtime check is necessary because the array size
 isn't constant, keep only the top-most seven bits (starting
@@ -3467,10 +3467,15 @@ build_new_1 (vec **placement, tree type, 
tree nelts,
}
 }
 
+  if (processing_template_decl)
+/* We've done pretty much all we can to check this non-dependent new-expr
+   ahead of time.  Any further work is unnecessary since (build_new just
+   discards the result) and/or unsuitable inside a template context.  */
+return void_node;
+
   /* If we found a simple case of PLACEMENT_EXPR above, then copy it
  into a temporary variable.  */
-  if (!processing_template_decl
-  && TREE_CODE (alloc_call) == CALL_EXPR
+  if (TREE_CODE (alloc_call) == CALL_EXPR
   && call_expr_nargs (alloc_call) == 2
   && TREE_CODE (TREE_TYPE (CALL_EXPR_ARG (alloc_call, 0))) == INTEGER_TYPE
   && TYPE_PTR_P (TREE_TYPE (CALL_EXPR_ARG (alloc_call, 1
@@ -3609,25 +3614,7 @@ build_new_1 (vec **placement, tree type, 
tree nelts,
  explicit_value_init_p = true;
}
 
-  if (processing_template_decl)
-   {
- /* Avoid an ICE when converting to a base in build_simple_base_path.
-We'll throw this all away anyway, and build_new will create
-a NEW_EXPR.  */
- tree t = fold_convert (build_pointer_type (elt_type), data_addr);
- /* build_value_init doesn't work in templates, and we don't need
-the initializer anyway since we're going to throw it away and
-rebuild it at instantiation time, so just build up a single
-constructor call to get any appropriate diagnostics.  */
- init_expr = cp_build_fold_indirect_ref (t);
- if (type_build_ctor_call (elt_type))
-   init_expr = build_special_member_call (init_expr,
-  complete_ctor_identifier,
-  init, elt_type,
-  LOOKUP_NORMAL,
-  complain);
-   }
-  else if (array_p)
+  if (array_p)
{
  tree vecinit = NULL_TREE;
  const size_t len = vec_safe_length (*init);
@@ -3721,8 +3708,7 @@ build_new_1 (vec **placement, tree type, 
tree nelts,
 object being initialized, replace them now and don't try to
 preevaluate.  */
  bool had_placeholder = false;
- if (!processing_template_decl
- && TREE_CODE (init_expr) == INIT_EXPR)
+ if (TREE_CODE (init_expr) == INIT_EXPR)
TREE_OPERAND (init_expr, 1)
  = replace_placeholders (TREE_OPERAND (init_expr, 1),
  TREE_OPERAND (init_expr, 0),
@@ -3760,7 +3746,7 @@ build_new_1 (vec **placement, tree type, 
tree nelts,
  alloc_fn,
  complain));
 
-  if (cleanup && init_expr && !processing_template_decl)
+  if (cleanup && init_expr)
/* Ack!  First we allocate the memory.  Then we set our sentry
   variable to true, and expand a cleanup that deletes the
   memory if sentry is true.  Then we run the constructor, and
-- 
2.42.0.482.g2e8e77cbac



[PATCH] c++: more ahead-of-time -Wparentheses warnings

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

-- >8 --

Now that we don't have to worry about looking thruogh NON_DEPENDENT_EXPR,
we can easily extend the -Wparentheses warning in convert_for_assignment
to consider (non-dependent) templated assignment operator expressions as
well, like r14-4111-g6e92a6a2a72d3b did in maybe_convert_cond.

gcc/cp/ChangeLog:

* cp-tree.h (is_assignment_op_expr_p): Declare.
* semantics.cc (is_assignment_op_expr_p): Generalize to return
true for assignment operator expression, not just one that
have been resolved to an operator overload.
(maybe_convert_cond): Remove now-redundant checks around
is_assignment_op_expr_p.
* typeck.cc (convert_for_assignment): Look through implicit
INDIRECT_REF in -Wparentheses warning logic, and generalize
to use is_assignment_op_expr_p.

gcc/testsuite/ChangeLog:

* g++.dg/warn/Wparentheses-13.C: Strengthen by not requiring
that the templates are instantiated for any of the -Wparentheses
warnings to be issued.
* g++.dg/warn/Wparentheses-23.C: Likewise.
* g++.dg/warn/Wparentheses-32.C: Remove xfails.
---
 gcc/cp/cp-tree.h|  1 +
 gcc/cp/semantics.cc | 22 +++--
 gcc/cp/typeck.cc|  7 ---
 gcc/testsuite/g++.dg/warn/Wparentheses-13.C |  2 --
 gcc/testsuite/g++.dg/warn/Wparentheses-23.C |  3 ---
 gcc/testsuite/g++.dg/warn/Wparentheses-32.C |  8 
 6 files changed, 21 insertions(+), 22 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 30fe716b109..c90ef883e52 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7875,6 +7875,7 @@ extern tree lambda_regenerating_args  (tree);
 extern tree most_general_lambda(tree);
 extern tree finish_omp_target  (location_t, tree, tree, bool);
 extern void finish_omp_target_clauses  (location_t, tree, tree *);
+extern bool is_assignment_op_expr_p(tree);
 
 /* in tree.cc */
 extern int cp_tree_operand_length  (const_tree);
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 72ec72de690..4b0038a4fc7 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -840,15 +840,20 @@ finish_goto_stmt (tree destination)
   return add_stmt (build_stmt (input_location, GOTO_EXPR, destination));
 }
 
-/* Returns true if CALL is a (possibly wrapped) CALL_EXPR or AGGR_INIT_EXPR
-   to operator= () that is written as an operator expression. */
-static bool
-is_assignment_op_expr_p (tree call)
+/* Returns true if T corresponds to an assignment operator expression.  */
+
+bool
+is_assignment_op_expr_p (tree t)
 {
-  if (call == NULL_TREE)
+  if (t == NULL_TREE)
 return false;
 
-  call = extract_call_expr (call);
+  if (TREE_CODE (t) == MODIFY_EXPR
+  || (TREE_CODE (t) == MODOP_EXPR
+ && TREE_CODE (TREE_OPERAND (t, 1)) == NOP_EXPR))
+return true;
+
+  tree call = extract_call_expr (t);
   if (call == NULL_TREE
   || call == error_mark_node
   || !CALL_EXPR_OPERATOR_SYNTAX (call))
@@ -882,10 +887,7 @@ maybe_convert_cond (tree cond)
   cond = convert_from_reference (cond);
 
   tree inner = REFERENCE_REF_P (cond) ? TREE_OPERAND (cond, 0) : cond;
-  if ((TREE_CODE (inner) == MODIFY_EXPR
-   || (TREE_CODE (inner) == MODOP_EXPR
-  && TREE_CODE (TREE_OPERAND (inner, 1)) == NOP_EXPR)
-   || is_assignment_op_expr_p (inner))
+  if (is_assignment_op_expr_p (inner)
   && warn_parentheses
   && !warning_suppressed_p (inner, OPT_Wparentheses)
   && warning_at (cp_expr_loc_or_input_loc (inner),
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 3b719326d76..0585b4a6bf0 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -10338,16 +10338,17 @@ convert_for_assignment (tree type, tree rhs,
 
   /* If -Wparentheses, warn about a = b = c when a has type bool and b
  does not.  */
+  tree inner_rhs = REFERENCE_REF_P (rhs) ? TREE_OPERAND (rhs, 0) : rhs;
   if (warn_parentheses
   && TREE_CODE (type) == BOOLEAN_TYPE
-  && TREE_CODE (rhs) == MODIFY_EXPR
-  && !warning_suppressed_p (rhs, OPT_Wparentheses)
+  && is_assignment_op_expr_p (inner_rhs)
+  && !warning_suppressed_p (inner_rhs, OPT_Wparentheses)
   && TREE_CODE (TREE_TYPE (rhs)) != BOOLEAN_TYPE
   && (complain & tf_warning)
   && warning_at (rhs_loc, OPT_Wparentheses,
 "suggest parentheses around assignment used as "
 "truth value"))
-suppress_warning (rhs, OPT_Wparentheses);
+suppress_warning (inner_rhs, OPT_Wparentheses);
 
   if (complain & tf_warning)
 warn_for_address_or_pointer_of_packed_member (type, rhs);
diff --git a/gcc/testsuite/g++.dg/warn/Wparentheses-13.C 
b/gcc/testsuite/g++.dg/warn/Wparentheses-13.C
index 22a139f23a4..d6438942c28 100644
--- 

[PATCH] c++/modules: fix up recent testcases

2023-10-25 Thread Patrick Palka
Tested on x86_64-pc-linux-gnu, does this look OK for trunk?

Declaring get() inline seems necessary to avoid link failure:

  /usr/bin/ld: /tmp/ccwdv6Co.o: in function `g3@pr105322.Decltype()':
  
decltype-1_b.C:(.text._ZW8pr105322W8Decltype2g3v[_ZW8pr105322W8Decltype2g3v]+0x18):
 undefined reference to `f@pr105322.Decltype()::A::get()'

Not sure if that's expected?

-- >8 --

This fixes some minor issues with the testcases from
r14-4806-g084addf8a700fa.

gcc/testsuite/ChangeLog:

* g++.dg/modules/decltype-1_a.C: Add missing } to dg-module-do
directive.  Declare f()::A::get() inline.
* g++.dg/modules/lambda-5_a.C: Add missing } to dg-module-do
directive.
---
 gcc/testsuite/g++.dg/modules/decltype-1_a.C | 4 ++--
 gcc/testsuite/g++.dg/modules/lambda-5_a.C   | 2 +-
 2 files changed, 3 insertions(+), 3 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..6512f151aae 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 }
 
@@ -7,7 +7,7 @@ export module pr105322.Decltype;
 
 auto f() {
   struct A { int m;
-int get () { return m; }
+inline int get () { return m; }
   };
   return A{};
 }
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.42.0.482.g2e8e77cbac



[PATCH] c++: another build_new_1 folding fix [PR111929]

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

-- >8 --

We also need to avoid folding 'outer_nelts_check' when in a template
context to prevent an ICE on the below testcase.  This patch achieves
this by replacing the fold_build2 call with build2 (cp_fully_fold will
later fold the overall expression if appropriate).

In passing, this patch removes an unnecessary call to convert on 'nelts'
since it should always already be a size_t (and 'convert' isn't the best
conversion entry point to use anyway since it doesn't take a complain
parameter.)

PR c++/111929

gcc/cp/ChangeLog:

* init.cc (build_new_1): Remove unnecessary call to convert
on 'nelts'.  Use build2 instead of fold_build2 for
'outer_nelts_checks'.

gcc/testsuite/ChangeLog:

* g++.dg/template/non-dependent28a.C: New test.
---
 gcc/cp/init.cc   | 8 
 gcc/testsuite/g++.dg/template/non-dependent28a.C | 8 
 2 files changed, 12 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/non-dependent28a.C

diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index 65d37c3c0c7..6444f0a8518 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -3261,7 +3261,7 @@ build_new_1 (vec **placement, tree type, 
tree nelts,
   max_outer_nelts = wi::udiv_trunc (max_size, inner_size);
   max_outer_nelts_tree = wide_int_to_tree (sizetype, max_outer_nelts);
 
-  size = build2 (MULT_EXPR, sizetype, size, convert (sizetype, nelts));
+  size = build2 (MULT_EXPR, sizetype, size, nelts);
 
   if (TREE_CODE (cst_outer_nelts) == INTEGER_CST)
{
@@ -3293,9 +3293,9 @@ build_new_1 (vec **placement, tree type, 
tree nelts,
- wi::clz (max_outer_nelts);
  max_outer_nelts = (max_outer_nelts >> shift) << shift;
 
-  outer_nelts_check = fold_build2 (LE_EXPR, boolean_type_node,
-  outer_nelts,
-  max_outer_nelts_tree);
+ outer_nelts_check = build2 (LE_EXPR, boolean_type_node,
+ outer_nelts,
+ max_outer_nelts_tree);
}
 }
 
diff --git a/gcc/testsuite/g++.dg/template/non-dependent28a.C 
b/gcc/testsuite/g++.dg/template/non-dependent28a.C
new file mode 100644
index 000..d32520c38ee
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/non-dependent28a.C
@@ -0,0 +1,8 @@
+// PR c++/111929
+
+struct A { operator int(); };
+
+template
+void f() {
+  new int[A()];
+}
-- 
2.42.0.482.g2e8e77cbac



Re: [PATCH] c++: build_new_1 and non-dep array size [PR111929]

2023-10-25 Thread Patrick Palka
On Tue, 24 Oct 2023, Jason Merrill wrote:

> On 10/24/23 13:03, Patrick Palka wrote:
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> > like the right approach?
> > 
> > -- >8 --
> > 
> > This PR is another instance of NON_DEPENDENT_EXPR having acted as an
> > "analysis barrier" for middle-end routines, and now that it's gone we
> > may end up passing weird templated trees (that have a generic tree code)
> > to the middle-end which leads to an ICE.  In the testcase below the
> > non-dependent array size 'var + 42' is expressed as an ordinary
> > PLUS_EXPR, but whose operand types have different precisions -- long and
> > int respectively -- naturally because templated trees encode only the
> > syntactic form of an expression devoid of e.g. implicit conversions
> > (typically).  This type incoherency triggers a wide_int assert during
> > the call to size_binop in build_new_1 which requires the operand types
> > have the same precision.
> > 
> > This patch fixes this by replacing our incremental folding of 'size'
> > within build_new_1 with a single call to cp_fully_fold (which is a no-op
> > in template context) once 'size' is fully built.
> 
> This is OK, but we could probably also entirely skip a lot of the calculation
> in a template, since we don't care about any values.  Can we skip the entire
> if (array_p) block?

That seems to be safe correctness-wise, but QOI-wise it'd mean we'd no
longer diagnose a too large array size ahead of time:

  template
  void f() {
new int[__SIZE_MAX__ / sizeof(int)];
  }

  : In function ‘void f()’:
  :3:37: error: size ‘(((sizetype)(18446744073709551615 / sizeof (int))) 
* 4)’ of array exceeds maximum object size ‘9223372036854775807’

(That we diagnose this ahead of time is thanks to the NON_DEPENDENT_EXPR
removal; previously 'nelts' was wrapped in NON_DEPENDENT_EXPR which
ironically prevented fold_non_dependent_expr from folding it to a
constant...)

> 
> > PR c++/111929
> > 
> > gcc/cp/ChangeLog:
> > 
> > * init.cc (build_new_1): Use convert, build2, build3 instead of
> > fold_convert, size_binop and fold_build3 when building 'size'.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/template/non-dependent28.C: New test.
> > ---
> >   gcc/cp/init.cc  | 9 +
> >   gcc/testsuite/g++.dg/template/non-dependent28.C | 6 ++
> >   2 files changed, 11 insertions(+), 4 deletions(-)
> >   create mode 100644 gcc/testsuite/g++.dg/template/non-dependent28.C
> > 
> > diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
> > index d48bb16c7c5..56c1b5e9f5e 100644
> > --- a/gcc/cp/init.cc
> > +++ b/gcc/cp/init.cc
> > @@ -3261,7 +3261,7 @@ build_new_1 (vec **placement, tree type,
> > tree nelts,
> > max_outer_nelts = wi::udiv_trunc (max_size, inner_size);
> > max_outer_nelts_tree = wide_int_to_tree (sizetype, max_outer_nelts);
> >   -  size = size_binop (MULT_EXPR, size, fold_convert (sizetype,
> > nelts));
> > +  size = build2 (MULT_EXPR, sizetype, size, convert (sizetype, nelts));
> >   if (TREE_CODE (cst_outer_nelts) == INTEGER_CST)
> > {
> > @@ -3344,7 +3344,7 @@ build_new_1 (vec **placement, tree type,
> > tree nelts,
> > /* Use a class-specific operator new.  */
> > /* If a cookie is required, add some extra space.  */
> > if (array_p && TYPE_VEC_NEW_USES_COOKIE (elt_type))
> > -   size = size_binop (PLUS_EXPR, size, cookie_size);
> > +   size = build2 (PLUS_EXPR, sizetype, size, cookie_size);
> > else
> > {
> >   cookie_size = NULL_TREE;
> > @@ -3358,8 +3358,8 @@ build_new_1 (vec **placement, tree type,
> > tree nelts,
> > if (cxx_dialect >= cxx11 && flag_exceptions)
> > errval = throw_bad_array_new_length ();
> > if (outer_nelts_check != NULL_TREE)
> > -   size = fold_build3 (COND_EXPR, sizetype, outer_nelts_check,
> > -   size, errval);
> > +   size = build3 (COND_EXPR, sizetype, outer_nelts_check, size, errval);
> > +  size = cp_fully_fold (size);
> > /* Create the argument list.  */
> > vec_safe_insert (*placement, 0, size);
> > /* Do name-lookup to find the appropriate operator.  */
> > @@ -3418,6 +3418,7 @@ build_new_1 (vec **placement, tree type,
> > tree nelts,
> > /* If size is zero e.g. due to type having zero size, try to
> >  preserve outer_nelts for constant expression evaluation
> >  purposes.  */
> > +  size = cp_fully_fold (size);
> > if (integer_zerop (size) && outer_nelts)
> > size = build2 (MULT_EXPR, TREE_TYPE (size), size, outer_nelts);
> >   diff --git a/gcc/testsuite/g++.dg/template/non-dependent28.C
> > b/gcc/testsuite/g++.dg/template/non-dependent28.C
> > new file mode 100644
> > index 000..3e45154f61d
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/template/non-dependent28.C
> > @@ -0,0 +1,6 @@
> > +// PR c++/111929
> > +
> > +template
> > +void f(long var) {
> > +  new int[var + 42];
> > +}
> 
> 

[pushed] c++: add fixed testcase [PR99804]

2023-10-25 Thread Patrick Palka
Tested on x86_64-pc-linux-gnu, pushed to trunk.

-- >8 --

We accept the non-dependent call f(e) here ever since the
NON_DEPENDENT_EXPR removal patch r14-4793-gdad311874ac3b3.
I haven't looked closely into why but I suspect wrapping 'e'
in a NON_DEPENDENT_EXPR was causing the argument conversion
to misbehave.

PR c++/99804

gcc/testsuite/ChangeLog:

* g++.dg/template/enum9.C: New test.
---
 gcc/testsuite/g++.dg/template/enum9.C | 12 
 1 file changed, 12 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/template/enum9.C

diff --git a/gcc/testsuite/g++.dg/template/enum9.C 
b/gcc/testsuite/g++.dg/template/enum9.C
new file mode 100644
index 000..c992cd505c2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/enum9.C
@@ -0,0 +1,12 @@
+// PR c++/99804
+
+struct S {
+  enum E { A, B } e : 1;
+  void f(E);
+  template void g() { f(e); }
+};
+
+int main() {
+  S s;
+  s.g();
+}
-- 
2.42.0.482.g2e8e77cbac



[PATCH] c++: build_new_1 and non-dep array size [PR111929]

2023-10-24 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
like the right approach?

-- >8 --

This PR is another instance of NON_DEPENDENT_EXPR having acted as an
"analysis barrier" for middle-end routines, and now that it's gone we
may end up passing weird templated trees (that have a generic tree code)
to the middle-end which leads to an ICE.  In the testcase below the
non-dependent array size 'var + 42' is expressed as an ordinary
PLUS_EXPR, but whose operand types have different precisions -- long and
int respectively -- naturally because templated trees encode only the
syntactic form of an expression devoid of e.g. implicit conversions
(typically).  This type incoherency triggers a wide_int assert during
the call to size_binop in build_new_1 which requires the operand types
have the same precision.

This patch fixes this by replacing our incremental folding of 'size'
within build_new_1 with a single call to cp_fully_fold (which is a no-op
in template context) once 'size' is fully built.

PR c++/111929

gcc/cp/ChangeLog:

* init.cc (build_new_1): Use convert, build2, build3 instead of
fold_convert, size_binop and fold_build3 when building 'size'.

gcc/testsuite/ChangeLog:

* g++.dg/template/non-dependent28.C: New test.
---
 gcc/cp/init.cc  | 9 +
 gcc/testsuite/g++.dg/template/non-dependent28.C | 6 ++
 2 files changed, 11 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/non-dependent28.C

diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index d48bb16c7c5..56c1b5e9f5e 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -3261,7 +3261,7 @@ build_new_1 (vec **placement, tree type, 
tree nelts,
   max_outer_nelts = wi::udiv_trunc (max_size, inner_size);
   max_outer_nelts_tree = wide_int_to_tree (sizetype, max_outer_nelts);
 
-  size = size_binop (MULT_EXPR, size, fold_convert (sizetype, nelts));
+  size = build2 (MULT_EXPR, sizetype, size, convert (sizetype, nelts));
 
   if (TREE_CODE (cst_outer_nelts) == INTEGER_CST)
{
@@ -3344,7 +3344,7 @@ build_new_1 (vec **placement, tree type, 
tree nelts,
   /* Use a class-specific operator new.  */
   /* If a cookie is required, add some extra space.  */
   if (array_p && TYPE_VEC_NEW_USES_COOKIE (elt_type))
-   size = size_binop (PLUS_EXPR, size, cookie_size);
+   size = build2 (PLUS_EXPR, sizetype, size, cookie_size);
   else
{
  cookie_size = NULL_TREE;
@@ -3358,8 +3358,8 @@ build_new_1 (vec **placement, tree type, 
tree nelts,
   if (cxx_dialect >= cxx11 && flag_exceptions)
errval = throw_bad_array_new_length ();
   if (outer_nelts_check != NULL_TREE)
-   size = fold_build3 (COND_EXPR, sizetype, outer_nelts_check,
-   size, errval);
+   size = build3 (COND_EXPR, sizetype, outer_nelts_check, size, errval);
+  size = cp_fully_fold (size);
   /* Create the argument list.  */
   vec_safe_insert (*placement, 0, size);
   /* Do name-lookup to find the appropriate operator.  */
@@ -3418,6 +3418,7 @@ build_new_1 (vec **placement, tree type, 
tree nelts,
   /* If size is zero e.g. due to type having zero size, try to
 preserve outer_nelts for constant expression evaluation
 purposes.  */
+  size = cp_fully_fold (size);
   if (integer_zerop (size) && outer_nelts)
size = build2 (MULT_EXPR, TREE_TYPE (size), size, outer_nelts);
 
diff --git a/gcc/testsuite/g++.dg/template/non-dependent28.C 
b/gcc/testsuite/g++.dg/template/non-dependent28.C
new file mode 100644
index 000..3e45154f61d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/non-dependent28.C
@@ -0,0 +1,6 @@
+// PR c++/111929
+
+template
+void f(long var) {
+  new int[var + 42];
+}
-- 
2.42.0.424.gceadf0f3cf



[PATCH v2 3/3] c++: note other candidates when diagnosing deletedness

2023-10-23 Thread Patrick Palka
With the previous two patches in place, we can now extend our
deletedness diagnostic to note the other considered candidates, e.g.:

  deleted16.C: In function 'int main()':
  deleted16.C:10:4: error: use of deleted function 'void f(int)'
 10 |   f(0);
|   ~^~~
  deleted16.C:5:6: note: declared here
  5 | void f(int) = delete;
|  ^
  deleted16.C:5:6: note: candidate: 'void f(int)' (deleted)
  deleted16.C:6:6: note: candidate: 'void f(...)'
  6 | void f(...);
|  ^
  deleted16.C:7:6: note: candidate: 'void f(int, int)'
  7 | void f(int, int);
|  ^
  deleted16.C:7:6: note:   candidate expects 2 arguments, 1 provided

For now, these these notes are disabled when a deleted special member
function is selected because it introduces a lot of new "cannot bind
reference" errors in the testsuite when noting non-viable candidates,
e.g. in cpp0x/initlist-opt1.C we would need to expect an error when
noting unviability of A(A&&).  (It'd be nice if we could downgrade such
errors into notes when noting candidates...)

gcc/cp/ChangeLog:

* call.cc (build_over_call): Call print_z_candidates when
diagnosing deletedness.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/deleted16.C: New test.
---
 gcc/cp/call.cc | 10 +-
 gcc/testsuite/g++.dg/cpp0x/deleted16.C | 24 
 2 files changed, 33 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/deleted16.C

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 3212d5268e0..1313d6516bd 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -9932,7 +9932,15 @@ build_over_call (struct z_candidate *cand, int flags, 
tsubst_flags_t complain)
   if (DECL_DELETED_FN (fn))
 {
   if (complain & tf_error)
-   mark_used (fn);
+   {
+ mark_used (fn);
+ /* Note the other candidates we considered unless we selected a
+special member function since the mismatch reasons for other
+candidates are usually uninteresting, e.g. rvalue vs lvalue
+reference binding .  */
+ if (cand->next && !special_memfn_p (fn))
+   print_z_candidates (input_location, cand, /*only_viable_p=*/false);
+   }
   return error_mark_node;
 }
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/deleted16.C 
b/gcc/testsuite/g++.dg/cpp0x/deleted16.C
new file mode 100644
index 000..55acbfd9188
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/deleted16.C
@@ -0,0 +1,24 @@
+// Verify we note other candidates when a deleted function is
+// selected by overload resolution.
+// { dg-do compile { target c++11 } }
+
+void f(int) = delete; // { dg-message "declared here|candidate" }
+void f(...); // { dg-message "candidate" }
+void f(int, int); // { dg-message "candidate" }
+
+// An example where the perfect candidate optimization causes us
+// to ignore function templates.
+void g(int) = delete; // { dg-message "declared here|candidate" }
+template void g(T); // { dg-message "candidate" }
+
+// An example where we have a strictly viable candidate and
+// an incompletely considered bad candidate.
+template void h(T, T) = delete; // { dg-message "declared 
here|candidate" }
+void h(int*, int) = delete; // { dg-message "candidate" }
+
+int main() {
+  f(0); // { dg-error "deleted" }
+  g(0); // { dg-error "deleted" }
+  h(1, 1); // { dg-error "deleted" }
+   // { dg-error "invalid conversion" "" { target *-*-* } .-1 } when 
noting 2nd cand
+}
-- 
2.42.0.424.gceadf0f3cf



[PATCH v2 2/3] c++: remember candidates that we ignored

2023-10-23 Thread Patrick Palka
During overload resolution, we sometimes outright ignore a function from
the overload set and leave no trace of it in the candidates list, for
example when we find a perfect non-template candidate we discard all
function templates, or when the callee is a template-id we discard all
non-template functions.  We should still however make note of these
unviable functions when diagnosing overload resolution failure, but
that's not possible if they're not present in the returned candidates
list.

To that end, this patch reworks add_candidates to add such ignored
functions to the list.  The new rr_ignored rejection reason is somewhat
of a catch-all; we could perhaps split it up into more specific rejection
reasons, but I leave that as future work.

gcc/cp/ChangeLog:

* call.cc (enum rejection_reason_code): Add rr_ignored.
(add_ignored_candidate): Define.
(ignored_candidate_p): Define.
(add_template_candidate_real): Do add_ignored_candidate
instead of returning NULL.
(splice_viable): Put ignored (unviable) candidates last.
(print_z_candidate): Handle ignored candidates.
(build_new_function_call): Refine shortcut that calls
cp_build_function_call_vec now that non-templates can
appear in the candidate list for a template-id call.
(add_candidates): Replace 'bad_fns' overload with 'bad_cands'
candidate list.  When not considering a candidate, add it
to the list as an ignored candidate.  Add all 'bad_cands'
to the overload set as well.

gcc/testsuite/ChangeLog:

* g++.dg/diagnostic/param-type-mismatch-2.C: Rename template
function test_7 that accidentally (perhaps) shares the same
name as its non-template callee.
* g++.dg/overload/error6.C: New test.
---
 gcc/cp/call.cc| 149 +-
 .../g++.dg/diagnostic/param-type-mismatch-2.C |  20 +--
 gcc/testsuite/g++.dg/overload/error6.C|   9 ++
 3 files changed, 132 insertions(+), 46 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/overload/error6.C

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 89d422f7220..3212d5268e0 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -441,7 +441,8 @@ enum rejection_reason_code {
   rr_template_unification,
   rr_invalid_copy,
   rr_inherited_ctor,
-  rr_constraint_failure
+  rr_constraint_failure,
+  rr_ignored,
 };
 
 struct conversion_info {
@@ -2224,6 +2225,34 @@ add_candidate (struct z_candidate **candidates,
   return cand;
 }
 
+/* FN is a function from the overload set that we outright didn't even consider
+   (for some reason); add it to the list as an unviable "ignored" candidate.  
*/
+
+static z_candidate *
+add_ignored_candidate (z_candidate **candidates, tree fn)
+{
+  /* No need to dynamically allocate these.  */
+  static const rejection_reason reason_ignored = { rr_ignored, {} };
+
+  struct z_candidate *cand = (struct z_candidate *)
+conversion_obstack_alloc (sizeof (struct z_candidate));
+
+  cand->fn = fn;
+  cand->reason = const_cast (_ignored);
+  cand->next = *candidates;
+  *candidates = cand;
+
+  return cand;
+}
+
+/* True iff CAND is a candidate added by add_ignored_candidate.  */
+
+static bool
+ignored_candidate_p (const z_candidate *cand)
+{
+  return cand->reason && cand->reason->code == rr_ignored;
+}
+
 /* Return the number of remaining arguments in the parameter list
beginning with ARG.  */
 
@@ -3471,7 +3500,7 @@ add_template_candidate_real (struct z_candidate 
**candidates, tree tmpl,
 }
 
   if (len < skip_without_in_chrg)
-return NULL;
+return add_ignored_candidate (candidates, tmpl);
 
   if (DECL_CONSTRUCTOR_P (tmpl) && nargs == 2
   && same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (first_arg),
@@ -3609,7 +3638,7 @@ add_template_candidate_real (struct z_candidate 
**candidates, tree tmpl,
   if (((flags & (LOOKUP_ONLYCONVERTING|LOOKUP_LIST_INIT_CTOR))
== LOOKUP_ONLYCONVERTING)
   && DECL_NONCONVERTING_P (fn))
-return NULL;
+return add_ignored_candidate (candidates, fn);
 
   if (DECL_CONSTRUCTOR_P (fn) && nargs == 2)
 {
@@ -3724,6 +3753,9 @@ splice_viable (struct z_candidate *cands,
   z_candidate *unviable = nullptr;
   z_candidate **unviable_tail = 
 
+  z_candidate *unviable_ignored = nullptr;
+  z_candidate **unviable_ignored_tail = _ignored;
+
   /* Be strict inside templates, since build_over_call won't actually
  do the conversions to get pedwarns.  */
   if (processing_template_decl)
@@ -3742,6 +3774,7 @@ splice_viable (struct z_candidate *cands,
 its viability.  */
   auto& tail = (cand->viable == 1 ? strictly_viable_tail
: cand->viable == -1 ? non_strictly_viable_tail
+   : ignored_candidate_p (cand) ? unviable_ignored_tail
: unviable_tail);
   *tail = cand;
   tail = >next;
@@ -3751,7 +3784,8 @@ splice_viable (struct z_candidate *cands,
   

[PATCH v2 1/3] c++: sort candidates according to viability

2023-10-23 Thread Patrick Palka
The second patch in this series is new and ensures that the candidates
list isn't mysteriously missing some candidates when noting other
candidates due to deletedness.

-- >8 --

This patch:

  * changes splice_viable to move the non-viable candidates to the end
of the list instead of removing them outright
  * makes tourney move the best candidate to the front of the candidate
list
  * adjusts print_z_candidates to preserve our behavior of printing only
viable candidates when diagnosing ambiguity
  * adds a parameter to print_z_candidates to control this default behavior
(the follow-up patch will want to print all candidates when diagnosing
deletedness)

Thus after this patch we have access to the entire candidate list through
the best viable candidate.

This change also happens to fix diagnostics for the below testcase where
we currently neglect to note the third candidate, since the presence of
the two unordered non-strictly viable candidates causes splice_viable to
prematurely get rid of the non-viable third candidate.

gcc/cp/ChangeLog:

* call.cc: Include "tristate.h".
(splice_viable): Sort the candidate list according to viability.
Don't remove non-viable candidates from the list.
(print_z_candidates): Add defaulted only_viable_p parameter.
By default only print non-viable candidates if there is no
viable candidate.
(tourney): Make 'candidates' parameter a reference.  Ignore
non-viable candidates.  Move the true champ to the front
of the candidates list, and update 'candidates' to point to
the front.

gcc/testsuite/ChangeLog:

* g++.dg/overload/error5.C: New test.
---
 gcc/cp/call.cc | 163 +++--
 gcc/testsuite/g++.dg/overload/error5.C |  12 ++
 2 files changed, 113 insertions(+), 62 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/overload/error5.C

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 2eb54b5b6ed..89d422f7220 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -43,6 +43,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "attribs.h"
 #include "decl.h"
 #include "gcc-rich-location.h"
+#include "tristate.h"
 
 /* The various kinds of conversion.  */
 
@@ -160,7 +161,7 @@ static struct obstack conversion_obstack;
 static bool conversion_obstack_initialized;
 struct rejection_reason;
 
-static struct z_candidate * tourney (struct z_candidate *, tsubst_flags_t);
+static struct z_candidate * tourney (struct z_candidate *&, tsubst_flags_t);
 static int equal_functions (tree, tree);
 static int joust (struct z_candidate *, struct z_candidate *, bool,
  tsubst_flags_t);
@@ -176,7 +177,8 @@ static void op_error (const op_location_t &, enum 
tree_code, enum tree_code,
 static struct z_candidate *build_user_type_conversion_1 (tree, tree, int,
 tsubst_flags_t);
 static void print_z_candidate (location_t, const char *, struct z_candidate *);
-static void print_z_candidates (location_t, struct z_candidate *);
+static void print_z_candidates (location_t, struct z_candidate *,
+   tristate = tristate::unknown ());
 static tree build_this (tree);
 static struct z_candidate *splice_viable (struct z_candidate *, bool, bool *);
 static bool any_strictly_viable (struct z_candidate *);
@@ -3700,68 +3702,60 @@ add_template_conv_candidate (struct z_candidate 
**candidates, tree tmpl,
 }
 
 /* The CANDS are the set of candidates that were considered for
-   overload resolution.  Return the set of viable candidates, or CANDS
-   if none are viable.  If any of the candidates were viable, set
+   overload resolution.  Sort CANDS so that the strictly viable
+   candidates appear first, followed by non-strictly viable candidates,
+   followed by unviable candidates.  Returns the first candidate
+   in this sorted list.  If any of the candidates were viable, set
*ANY_VIABLE_P to true.  STRICT_P is true if a candidate should be
-   considered viable only if it is strictly viable.  */
+   considered viable only if it is strictly viable when setting
+   *ANY_VIABLE_P.  */
 
 static struct z_candidate*
 splice_viable (struct z_candidate *cands,
   bool strict_p,
   bool *any_viable_p)
 {
-  struct z_candidate *viable;
-  struct z_candidate **last_viable;
-  struct z_candidate **cand;
-  bool found_strictly_viable = false;
+  z_candidate *strictly_viable = nullptr;
+  z_candidate **strictly_viable_tail = _viable;
+
+  z_candidate *non_strictly_viable = nullptr;
+  z_candidate **non_strictly_viable_tail = _strictly_viable;
+
+  z_candidate *unviable = nullptr;
+  z_candidate **unviable_tail = 
 
   /* Be strict inside templates, since build_over_call won't actually
  do the conversions to get pedwarns.  */
   if (processing_template_decl)
 strict_p = true;
 
-  viable = NULL;
-  last_viable = 
-  *any_viable_p = false;

[PATCH] c++: cp_stabilize_reference and non-dep exprs [PR111919]

2023-10-23 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
for trunk?

-- >8 --

After the removal of NON_DEPENDENT_EXPR, cp_stabilize_reference which
used to just exit early for NON_DEPENDENT_EXPR is now more prone to
passing a weird templated tree to middle-end routines, which leads to a
crash from contains_placeholder_p in the testcase below.  It seems the
best fix is to just disable cp_stabilize_reference when in a template
context like we already do for cp_save_expr; it seems SAVE_EXPR should
never appear in a templated tree (since e.g. tsubst doesn't handle it).

PR c++/111919

gcc/cp/ChangeLog:

* tree.cc (cp_stabilize_reference): Do nothing when
processing_template_decl.

gcc/testsuite/ChangeLog:

* g++.dg/template/non-dependent27.C: New test.
---
 gcc/cp/tree.cc  | 4 
 gcc/testsuite/g++.dg/template/non-dependent27.C | 8 
 2 files changed, 12 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/template/non-dependent27.C

diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index a3d61d3e7c9..417c92ba76f 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -408,6 +408,10 @@ bitfield_p (const_tree ref)
 tree
 cp_stabilize_reference (tree ref)
 {
+  if (processing_template_decl)
+/* As in cp_save_expr.  */
+return ref;
+
   STRIP_ANY_LOCATION_WRAPPER (ref);
   switch (TREE_CODE (ref))
 {
diff --git a/gcc/testsuite/g++.dg/template/non-dependent27.C 
b/gcc/testsuite/g++.dg/template/non-dependent27.C
new file mode 100644
index 000..cf7af6e6425
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/non-dependent27.C
@@ -0,0 +1,8 @@
+// PR c++/111919
+
+int i[3];
+
+template
+void f() {
+  i[42 / (int) sizeof (T)] |= 0;
+}
-- 
2.42.0.424.gceadf0f3cf



Re: [PATCH v24 33/33] libstdc++: Optimize std::is_invocable compilation performance

2023-10-23 Thread Patrick Palka
On Mon, 23 Oct 2023, Ken Matsui wrote:

> On Mon, Oct 23, 2023 at 10:05 AM Patrick Palka  wrote:
>   On Fri, Oct 20, 2023 at 12:22 PM Ken Matsui  wrote:
>   >
>   > This patch optimizes the compilation performance of std::is_invocable
>   > by dispatching to the new __is_invocable built-in trait.
>   >
>   > libstdc++-v3/ChangeLog:
>   >
>   >         * include/std/type_traits (is_invocable): Use __is_invocable
>   >         built-in trait.
> 
>   Nice!  We should use the trait directly in is_invocable_v too.
> 
> 
> Thank you! But we want to take account of static_assert’s in is_invocable, so 
> I think we cannot use the built-in directly?

Good point, I guess that's a great reason to improvement the diagnostic
that check_trait_type emits: it'd speed up the class template version
because we could get rid of the static_asserts (without regressing
diagnostic quality), and it'd speed up the variable template version
because we could use the built-in directly there.

Your patch LGTM as is though, that could be a follow-up if anything.

> 
> 
>   >         * testsuite/20_util/is_invocable/incomplete_args_neg.cc: 
> Handle
>   >         the new error from __is_invocable.
>   >         * testsuite/20_util/is_invocable/incomplete_neg.cc: Likewise.
>   >
>   > Signed-off-by: Ken Matsui 
>   > ---
>   >  libstdc++-v3/include/std/type_traits                        | 6 
> ++
>   >  .../testsuite/20_util/is_invocable/incomplete_args_neg.cc   | 1 +
>   >  .../testsuite/20_util/is_invocable/incomplete_neg.cc        | 1 +
>   >  3 files changed, 8 insertions(+)
>   >
>   > diff --git a/libstdc++-v3/include/std/type_traits 
> b/libstdc++-v3/include/std/type_traits
>   > index 75a94cb8d7e..91851b78c7e 100644
>   > --- a/libstdc++-v3/include/std/type_traits
>   > +++ b/libstdc++-v3/include/std/type_traits
>   > @@ -3167,9 +3167,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>   >      using invoke_result_t = typename invoke_result<_Fn, 
> _Args...>::type;
>   >
>   >    /// std::is_invocable
>   > +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_invocable)
>   > +  template
>   > +    struct is_invocable
>   > +    : public __bool_constant<__is_invocable(_Fn, _ArgTypes...)>
>   > +#else
>   >    template
>   >      struct is_invocable
>   >      : __is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, 
> void>::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_invocable/incomplete_args_neg.cc 
> b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc
>   > index 34d1d9431d1..3f9e5274f3c 100644
>   > --- 
> a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc
>   > +++ 
> b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc
>   > @@ -18,6 +18,7 @@
>   >  // <http://www.gnu.org/licenses/>.
>   >
>   >  // { dg-error "must be a complete class" "" { target *-*-* } 0 }
>   > +// { dg-prune-output "invalid use of incomplete type" }
>   >
>   >  #include 
>   >
>   > diff --git 
> a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc 
> b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc
>   > index e1e54d25ee5..92af48c48b6 100644
>   > --- a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc
>   > +++ b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc
>   > @@ -18,6 +18,7 @@
>   >  // <http://www.gnu.org/licenses/>.
>   >
>   >  // { dg-error "must be a complete class" "" { target *-*-* } 0 }
>   > +// { dg-prune-output "invalid use of incomplete type" }
>   >
>   >  #include 
>   >
>   > --
>   > 2.42.0
>   >
> 
> 
> 

Re: [PATCH v24 33/33] libstdc++: Optimize std::is_invocable compilation performance

2023-10-23 Thread Patrick Palka
On Fri, Oct 20, 2023 at 12:22 PM Ken Matsui  wrote:
>
> This patch optimizes the compilation performance of std::is_invocable
> by dispatching to the new __is_invocable built-in trait.
>
> libstdc++-v3/ChangeLog:
>
> * include/std/type_traits (is_invocable): Use __is_invocable
> built-in trait.

Nice!  We should use the trait directly in is_invocable_v too.

> * testsuite/20_util/is_invocable/incomplete_args_neg.cc: Handle
> the new error from __is_invocable.
> * testsuite/20_util/is_invocable/incomplete_neg.cc: Likewise.
>
> Signed-off-by: Ken Matsui 
> ---
>  libstdc++-v3/include/std/type_traits| 6 ++
>  .../testsuite/20_util/is_invocable/incomplete_args_neg.cc   | 1 +
>  .../testsuite/20_util/is_invocable/incomplete_neg.cc| 1 +
>  3 files changed, 8 insertions(+)
>
> diff --git a/libstdc++-v3/include/std/type_traits 
> b/libstdc++-v3/include/std/type_traits
> index 75a94cb8d7e..91851b78c7e 100644
> --- a/libstdc++-v3/include/std/type_traits
> +++ b/libstdc++-v3/include/std/type_traits
> @@ -3167,9 +3167,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>  using invoke_result_t = typename invoke_result<_Fn, _Args...>::type;
>
>/// std::is_invocable
> +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_invocable)
> +  template
> +struct is_invocable
> +: public __bool_constant<__is_invocable(_Fn, _ArgTypes...)>
> +#else
>template
>  struct is_invocable
>  : __is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, void>::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_invocable/incomplete_args_neg.cc 
> b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc
> index 34d1d9431d1..3f9e5274f3c 100644
> --- a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc
> +++ b/libstdc++-v3/testsuite/20_util/is_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" }
>
>  #include 
>
> diff --git a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc 
> b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc
> index e1e54d25ee5..92af48c48b6 100644
> --- a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc
> +++ b/libstdc++-v3/testsuite/20_util/is_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.42.0
>



Re: [PATCH v23 31/33] libstdc++: Optimize std::is_pointer compilation performance

2023-10-23 Thread Patrick Palka
On Sun, 22 Oct 2023, Ken Matsui wrote:

> Hi Patrick,
> 
> There is an issue with the code in
> libstdc++-v3/include/bits/cpp_type_traits.h. Specifically, Clang 16
> does not accept the code, while Clang 17 does. Given that we aim to
> support the last two versions of Clang, we need to ensure that Clang
> 16 accepts this code. Can you please advise on the best course of
> action regarding this matter?

The following workaround seems to make Clang happy:

#include 

template
struct __is_pointer : std::bool_constant { };

> 
> https://godbolt.org/z/PbxhYcb7q
> 
> Sincerely,
> Ken Matsui
> 
> On Fri, Oct 20, 2023 at 7:12 AM Ken Matsui  wrote:
> >
> > This patch optimizes the compilation performance of std::is_pointer
> > by dispatching to the new __is_pointer built-in trait.
> >
> > libstdc++-v3/ChangeLog:
> >
> > * include/bits/cpp_type_traits.h (__is_pointer): Use __is_pointer
> > built-in trait.
> > * include/std/type_traits (is_pointer): Likewise. Optimize its
> > implementation.
> > (is_pointer_v): Likewise.
> >
> > Co-authored-by: Jonathan Wakely 
> > Signed-off-by: Ken Matsui 
> > ---
> >  libstdc++-v3/include/bits/cpp_type_traits.h |  8 
> >  libstdc++-v3/include/std/type_traits| 44 +
> >  2 files changed, 44 insertions(+), 8 deletions(-)
> >
> > diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h 
> > b/libstdc++-v3/include/bits/cpp_type_traits.h
> > index 4312f32a4e0..246f2cc0b17 100644
> > --- a/libstdc++-v3/include/bits/cpp_type_traits.h
> > +++ b/libstdc++-v3/include/bits/cpp_type_traits.h
> > @@ -363,6 +363,13 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
> >//
> >// Pointer types
> >//
> > +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
> > +  template
> > +struct __is_pointer : __truth_type<__is_pointer(_Tp)>
> > +{
> > +  enum { __value = __is_pointer(_Tp) };
> > +};
> > +#else
> >template
> >  struct __is_pointer
> >  {
> > @@ -376,6 +383,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
> >enum { __value = 1 };
> >typedef __true_type __type;
> >  };
> > +#endif
> >
> >//
> >// An arithmetic type is an integer type or a floating point type
> > diff --git a/libstdc++-v3/include/std/type_traits 
> > b/libstdc++-v3/include/std/type_traits
> > index 0641ecfdf2b..75a94cb8d7e 100644
> > --- a/libstdc++-v3/include/std/type_traits
> > +++ b/libstdc++-v3/include/std/type_traits
> > @@ -542,19 +542,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> >  : public true_type { };
> >  #endif
> >
> > -  template
> > -struct __is_pointer_helper
> > +  /// is_pointer
> > +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
> > +  template
> > +struct is_pointer
> > +: public __bool_constant<__is_pointer(_Tp)>
> > +{ };
> > +#else
> > +  template
> > +struct is_pointer
> >  : public false_type { };
> >
> >template
> > -struct __is_pointer_helper<_Tp*>
> > +struct is_pointer<_Tp*>
> >  : public true_type { };
> >
> > -  /// is_pointer
> >template
> > -struct is_pointer
> > -: public __is_pointer_helper<__remove_cv_t<_Tp>>::type
> > -{ };
> > +struct is_pointer<_Tp* const>
> > +: public true_type { };
> > +
> > +  template
> > +struct is_pointer<_Tp* volatile>
> > +: public true_type { };
> > +
> > +  template
> > +struct is_pointer<_Tp* const volatile>
> > +: public true_type { };
> > +#endif
> >
> >/// is_lvalue_reference
> >template
> > @@ -3252,8 +3266,22 @@ template 
> >inline constexpr bool is_array_v<_Tp[_Num]> = true;
> >  #endif
> >
> > +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
> > +template 
> > +  inline constexpr bool is_pointer_v = __is_pointer(_Tp);
> > +#else
> >  template 
> > -  inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
> > +  inline constexpr bool is_pointer_v = false;
> > +template 
> > +  inline constexpr bool is_pointer_v<_Tp*> = true;
> > +template 
> > +  inline constexpr bool is_pointer_v<_Tp* const> = true;
> > +template 
> > +  inline constexpr bool is_pointer_v<_Tp* volatile> = true;
> > +template 
> > +  inline constexpr bool is_pointer_v<_Tp* const volatile> = true;
> > +#endif
> > +
> >  template 
> >inline constexpr bool is_lvalue_reference_v = false;
> >  template 
> > --
> > 2.42.0
> >
> 
> 

[pushed] objc++: type/expr tsubst conflation [PR111920]

2023-10-22 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linux-gnu, pushed to
trunk as obvious.

-- >8 --

After r14-4796-g3e3d73ed5e85e7, tsubst_copy_and_build (now named
tsubst_expr) no longer dispatches to tsubst for type trees, and
callers have to do it themselves if appropriate.  This patch makes
some overlooked adjustments to Objective-C++-specific code paths.

PR objc++/111920

gcc/cp/ChangeLog:

* pt.cc (tsubst_expr) : Use tsubst instead
of tsubst_expr.

gcc/objcp/ChangeLog:

* objcp-lang.cc (objcp_tsubst_expr) :
Use tsubst instead of tsubst_expr for type operands.
---
 gcc/cp/pt.cc|  2 +-
 gcc/objcp/objcp-lang.cc | 10 --
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 210c6cb9e4d..1c1c9313118 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -20261,7 +20261,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
op1 = TREE_OPERAND (t, 0);
++cp_unevaluated_operand;
++c_inhibit_evaluation_warnings;
-   op1 = tsubst_expr (op1, args, complain, in_decl);
+   op1 = tsubst (op1, args, complain, in_decl);
--cp_unevaluated_operand;
--c_inhibit_evaluation_warnings;
RETURN (objc_build_encode_expr (op1));
diff --git a/gcc/objcp/objcp-lang.cc b/gcc/objcp/objcp-lang.cc
index 5b04cd66290..ee39aece848 100644
--- a/gcc/objcp/objcp-lang.cc
+++ b/gcc/objcp/objcp-lang.cc
@@ -66,8 +66,14 @@ objcp_tsubst_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
 RECURSE (TREE_OPERAND (t, 2)), NULL);
 
 case CLASS_REFERENCE_EXPR:
-  return objc_get_class_reference
-   (RECURSE (TREE_OPERAND (t, 0)));
+  {
+   tree ident = TREE_OPERAND (t, 0);
+   if (TYPE_P (ident))
+ ident = tsubst (ident, args, complain, in_decl);
+   else
+ ident = RECURSE (ident);
+   return objc_get_class_reference (ident);
+  }
 
 default:
   break;
-- 
2.42.0.424.gceadf0f3cf



Re: [PATCH v23 32/33] c++: Implement __is_invocable built-in trait

2023-10-20 Thread Patrick Palka
On Fri, 20 Oct 2023, Patrick Palka wrote:

> On Fri, 20 Oct 2023, Patrick Palka wrote:
> 
> > On Fri, 20 Oct 2023, Ken Matsui wrote:
> > 
> > > This patch implements built-in trait for std::is_invocable.
> > 
> > Nice!  My email client unfortunately ate my first review attempt, so
> > apologies for my brevity this time around.
> > 
> > > 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.
> > >   (is_invocable_p): New function.
> > >   * method.h: New file to export build_trait_object in method.cc.
> > > 
> > > 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.
> > > 
> > > Signed-off-by: Ken Matsui 
> > > ---
> > >  gcc/cp/constraint.cc |   6 +
> > >  gcc/cp/cp-trait.def  |   1 +
> > >  gcc/cp/method.h  |  28 ++
> > >  gcc/cp/semantics.cc  | 135 +
> > >  gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
> > >  gcc/testsuite/g++.dg/ext/is_invocable1.C | 337 +++
> > >  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 +++
> > >  9 files changed, 733 insertions(+)
> > >  create mode 100644 gcc/cp/method.h
> > >  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 9fce36e12d1..29bf548d30a 100644
> > > --- a/gcc/cp/constraint.cc
> > > +++ b/gcc/cp/constraint.cc
> > > @@ -3754,6 +3754,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 05514a51c21..b8b7608c122 100644
> > > --- a/gcc/cp/cp-trait.def
> > > +++ b/gcc/cp/cp-trait.def
> > > @@ -71,6 +71,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/method.h b/gcc/cp/method.h
> > > new file mode 100644
> > > index 000..1aec8ec5cfd
> > > --- /dev/null
> > > +++ b/gcc/cp/method.h
> > > @@ -0,0 +1,28 @@
> > > +/* Functions exported by method.cc.
> > > +   Copyright (C) 2023 Free Software Foundation, Inc.
> > > +
> > > +This file is part of GCC.
> > > +
> > > +GCC is free software; you can redistribute it and/or modify
> > > +it under the terms of the GNU General Public License as published by
> > > +the Free Software Foundation; either version 3, or (at your option)
> > > +any later version.
> > > +
> > > +GCC is distributed in the hope that it will be useful,
> > > +but WITHOUT ANY WARRANTY; without even the implied warranty of
> > 

Re: [PATCH v23 32/33] c++: Implement __is_invocable built-in trait

2023-10-20 Thread Patrick Palka
On Fri, 20 Oct 2023, Patrick Palka wrote:

> On Fri, 20 Oct 2023, Ken Matsui wrote:
> 
> > This patch implements built-in trait for std::is_invocable.
> 
> Nice!  My email client unfortunately ate my first review attempt, so
> apologies for my brevity this time around.
> 
> > 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.
> > (is_invocable_p): New function.
> > * method.h: New file to export build_trait_object in method.cc.
> > 
> > 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.
> > 
> > Signed-off-by: Ken Matsui 
> > ---
> >  gcc/cp/constraint.cc |   6 +
> >  gcc/cp/cp-trait.def  |   1 +
> >  gcc/cp/method.h  |  28 ++
> >  gcc/cp/semantics.cc  | 135 +
> >  gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
> >  gcc/testsuite/g++.dg/ext/is_invocable1.C | 337 +++
> >  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 +++
> >  9 files changed, 733 insertions(+)
> >  create mode 100644 gcc/cp/method.h
> >  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 9fce36e12d1..29bf548d30a 100644
> > --- a/gcc/cp/constraint.cc
> > +++ b/gcc/cp/constraint.cc
> > @@ -3754,6 +3754,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 05514a51c21..b8b7608c122 100644
> > --- a/gcc/cp/cp-trait.def
> > +++ b/gcc/cp/cp-trait.def
> > @@ -71,6 +71,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/method.h b/gcc/cp/method.h
> > new file mode 100644
> > index 000..1aec8ec5cfd
> > --- /dev/null
> > +++ b/gcc/cp/method.h
> > @@ -0,0 +1,28 @@
> > +/* Functions exported by method.cc.
> > +   Copyright (C) 2023 Free Software Foundation, Inc.
> > +
> > +This file is part of GCC.
> > +
> > +GCC is free software; you can redistribute it and/or modify
> > +it under the terms of the GNU General Public License as published by
> > +the Free Software Foundation; either version 3, or (at your option)
> > +any later version.
> > +
> > +GCC is distributed in the hope that it will be useful,
> > +but WITHOUT ANY WARRANTY; without even the implied warranty of
> > +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > +GNU General Public License for more details.
> > +
> > +You should have received a copy of the GNU General Public License
> > +along with GCC; see the file COPYING3.  If not see
> > +<http://www.gnu.org/licenses/>.  */
> > +
> > +#ifndef GCC_CP_METHOD_H
> > +#define GCC_CP_METHOD_H 1
> > +
> > +#include "tree.h"
> >

Re: [PATCH v23 32/33] c++: Implement __is_invocable built-in trait

2023-10-20 Thread Patrick Palka
On Fri, 20 Oct 2023, Ken Matsui wrote:

> This patch implements built-in trait for std::is_invocable.

Nice!  My email client unfortunately ate my first review attempt, so
apologies for my brevity this time around.

> 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.
>   (is_invocable_p): New function.
>   * method.h: New file to export build_trait_object in method.cc.
> 
> 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.
> 
> Signed-off-by: Ken Matsui 
> ---
>  gcc/cp/constraint.cc |   6 +
>  gcc/cp/cp-trait.def  |   1 +
>  gcc/cp/method.h  |  28 ++
>  gcc/cp/semantics.cc  | 135 +
>  gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
>  gcc/testsuite/g++.dg/ext/is_invocable1.C | 337 +++
>  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 +++
>  9 files changed, 733 insertions(+)
>  create mode 100644 gcc/cp/method.h
>  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 9fce36e12d1..29bf548d30a 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -3754,6 +3754,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 05514a51c21..b8b7608c122 100644
> --- a/gcc/cp/cp-trait.def
> +++ b/gcc/cp/cp-trait.def
> @@ -71,6 +71,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/method.h b/gcc/cp/method.h
> new file mode 100644
> index 000..1aec8ec5cfd
> --- /dev/null
> +++ b/gcc/cp/method.h
> @@ -0,0 +1,28 @@
> +/* Functions exported by method.cc.
> +   Copyright (C) 2023 Free Software Foundation, Inc.
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify
> +it under the terms of the GNU General Public License as published by
> +the Free Software Foundation; either version 3, or (at your option)
> +any later version.
> +
> +GCC is distributed in the hope that it will be useful,
> +but WITHOUT ANY WARRANTY; without even the implied warranty of
> +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +GNU General Public License for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +.  */
> +
> +#ifndef GCC_CP_METHOD_H
> +#define GCC_CP_METHOD_H 1
> +
> +#include "tree.h"
> +
> +/* In method.cc  */
> +extern tree build_trait_object (tree type);

Since other method.cc exports are already declared in cp-tree.h, for now
let's just declare this in cp-tree.h as well (under build_stub_object)
instead of creating a new header file.

> +
> +#endif  /* GCC_CP_METHOD_H  */
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index 7cccbae5287..cc2e400531a 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -45,6 +45,10 @@ along with GCC; see the file COPYING3.  If not see
>  #include "gomp-constants.h"
>  #include "predict.h"
>  #include "memmodel.h"
> +#include "method.h"
> +
> +#include "print-tree.h"
> +#include "tree-pretty-print.h"
>  
>  /* There routines provide a modular interface to perform many parsing
> operations.  They may therefore be used during actual parsing, or
> @@ -11714,6 +11718,133 @@ classtype_has_nothrow_assign_or_copy_p (tree type, 
> bool assign_p)
>return saw_copy;
>  }
>  
> +/* 

Re: [PATCH] c++/modules: ICE with lambda initializing local var [PR105322]

2023-10-20 Thread Patrick Palka
On Fri, 20 Oct 2023, Nathan Sidwell wrote:

> Thanks for looking at this, but your patch is essentially papering over the
> problem.
> 
> It took me a while to figure out, but the clue was that things like
> 'decltype(f()).m' worked, but 'decltype(f()){0}' did not.  The CONSTRUCTOR
> node is the exception to the rule that required an expression node's type to
> be streamed after the node's operands.  We want the opposite for CTORS.
> 
> I'll commit this once bootstrapped.

Very interesting, thanks a lot!  It's awesome that both testcases could
be fixed simultaneously after all :)

> 
> nathan
> 
> On 10/18/23 12:28, Patrick Palka wrote:
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > trunk?
> > 
> > -- >8 --
> > 
> > For a local variable initialized by a lambda:
> > 
> >auto f = []{};
> > 
> > The corresponding BLOCK_VARS contains the variable declaration first,
> > followed by the closure type declaration, consistent with the
> > syntactical order.  This however means that a use of the closure type
> > appears (in the variable type/initializer) before the declaration of the
> > type.  This ends up causing an ICE when streaming the BLOCK_VARS of f1
> > below because we stream (by value) the CONSTRUCTOR initializer of g1 --
> > which contains components of the closure type -- before we've streamed
> > the declaration defining the closure type.  The following comment in
> > module.cc seems relevant:
> > 
> >/* We want to stream the type of a expression-like nodes /after/
> >   we've streamed the operands.  The type often contains (bits
> >   of the) types of the operands, and with things like decltype
> >   and noexcept in play, we really want to stream the decls
> >   defining the type before we try and stream the type on its
> >   own.  Otherwise we can find ourselves trying to read in a
> >   decl, when we're already partially reading in a component of
> >   its type.  And that's bad.  */
> > 
> > This patch narrowly fixes this issue by special casing closure type
> > declarations in add_decl_to_level.  (A loop is needed since there could
> > be multiple variable declarations with an unprocessed initializer in
> > light of structured bindings.)
> > 
> > PR c++/105322
> > 
> > gcc/cp/ChangeLog:
> > 
> > * name-lookup.cc (add_decl_to_level): When adding a closure
> > type declaration to a block scope, add it before rather than
> > after any variable declarations whose initializer we're still
> > processing.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/modules/lambda-5_a.C: New test.
> > * g++.dg/modules/lambda-5_b.C: New test.
> > ---
> >   gcc/cp/name-lookup.cc | 19 ---
> >   gcc/testsuite/g++.dg/modules/lambda-5_a.C | 23 +++
> >   gcc/testsuite/g++.dg/modules/lambda-5_b.C | 10 ++
> >   3 files changed, 49 insertions(+), 3 deletions(-)
> >   create mode 100644 gcc/testsuite/g++.dg/modules/lambda-5_a.C
> >   create mode 100644 gcc/testsuite/g++.dg/modules/lambda-5_b.C
> > 
> > diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
> > index a8b9229b29e..bb00baaf9f4 100644
> > --- a/gcc/cp/name-lookup.cc
> > +++ b/gcc/cp/name-lookup.cc
> > @@ -391,9 +391,22 @@ add_decl_to_level (cp_binding_level *b, tree decl)
> > gcc_assert (b->names != decl);
> >   /* We build up the list in reverse order, and reverse it later if
> > - necessary.  */
> > -  TREE_CHAIN (decl) = b->names;
> > -  b->names = decl;
> > + necessary.  If we're adding a lambda closure type to a block
> > + scope as part of a local variable initializer, then make sure
> > + we declare the type before the variable; modules expects that
> > + we see a type declaration before a use of the type.  */
> > +  tree *prev = >names;
> > +  if (b->kind == sk_block
> > +  && !processing_template_decl
> > +  && TREE_CODE (decl) == TYPE_DECL
> > +  && LAMBDA_TYPE_P (TREE_TYPE (decl)))
> > +while (*prev && VAR_P (*prev)
> > +  && !DECL_EXTERNAL (*prev)
> > +  && !DECL_INITIALIZED_P (*prev))
> > +  prev = _CHAIN (*prev);
> > +
> > +  TREE_CHAIN (decl) = *prev;
> > +  *prev = decl;
> >   /* If appropriate, add decl to separate list of statics.  We include
> >extern variables because they might turn out to be static l

Re: [PATCH v23 02/33] c-family, c++: Look up built-in traits via identifier node

2023-10-20 Thread Patrick Palka
On Fri, Oct 20, 2023 at 10:02 AM Ken Matsui  wrote:
>
> Since RID_MAX soon reaches 255 and all built-in traits are used approximately
> once in a C++ translation unit, this patch removes all RID values for built-in
> traits and uses the identifier node to look up the specific trait.  Rather
> than holding traits as keywords, we set all trait identifiers as cik_trait,
> which is a new cp_identifier_kind.  As cik_reserved_for_udlit was unused and
> cp_identifier_kind is 3 bits, we replaced the unused field with the new
> cik_trait.  Also, the later patch handles a subsequent token to the built-in
> identifier so that we accept the use of non-function-like built-in 
> traitreviewed but can be pushed incrementally if anything
> identifiers.

Thanks a lot, patches 1-31 in this series LGTM.




>
> gcc/c-family/ChangeLog:
>
> * c-common.cc (c_common_reswords): Remove all mappings of
> built-in traits.
> * c-common.h (enum rid): Remove all RID values for built-in traits.
>
> gcc/cp/ChangeLog:
>
> * cp-objcp-common.cc (names_builtin_p): Remove all RID value
> cases for built-in traits.  Check for built-in traits via
> the new cik_trait kind.
> * cp-tree.h (enum cp_trait_kind): Set its underlying type to
> addr_space_t.
> (struct cp_trait): New struct to hold trait information.
> (cp_traits): New array to hold a mapping to all traits.
> (cik_reserved_for_udlit): Rename to ...
> (cik_trait): ... this.
> (IDENTIFIER_ANY_OP_P): Exclude cik_trait.
> (IDENTIFIER_TRAIT_P): New macro to detect cik_trait.
> * lex.cc (cp_traits): Define its values, declared in cp-tree.h.
> (init_cp_traits): New function to set cik_trait and
> IDENTIFIER_CP_INDEX for all built-in trait identifiers.
> (cxx_init): Call init_cp_traits function.
> * parser.cc (cp_lexer_lookup_trait): New function to look up a
> built-in trait by IDENTIFIER_CP_INDEX.
> (cp_lexer_lookup_trait_expr): Likewise, look up an
> expression-yielding built-in trait.
> (cp_lexer_lookup_trait_type): Likewise, look up a type-yielding
> built-in trait.
> (cp_keyword_starts_decl_specifier_p): Remove all RID value cases
> for built-in traits.
> (cp_lexer_next_token_is_decl_specifier_keyword): Handle
> type-yielding built-in traits.
> (cp_parser_primary_expression): Remove all RID value cases for
> built-in traits.  Handle expression-yielding built-in traits.
> (cp_parser_trait): Handle cp_trait instead of enum rid.
> (cp_parser_simple_type_specifier): Remove all RID value cases
> for built-in traits.  Handle type-yielding built-in traits.
>
> Co-authored-by: Patrick Palka 
> Signed-off-by: Ken Matsui 
> ---
>  gcc/c-family/c-common.cc  |   7 ---
>  gcc/c-family/c-common.h   |   5 --
>  gcc/cp/cp-objcp-common.cc |   8 +--
>  gcc/cp/cp-tree.h  |  32 +---
>  gcc/cp/lex.cc |  34 
>  gcc/cp/parser.cc  | 105 +++---
>  6 files changed, 126 insertions(+), 65 deletions(-)
>
> diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
> index f044db5b797..21fd333ef57 100644
> --- a/gcc/c-family/c-common.cc
> +++ b/gcc/c-family/c-common.cc
> @@ -508,13 +508,6 @@ const struct c_common_resword c_common_reswords[] =
>{ "wchar_t", RID_WCHAR,  D_CXXONLY },
>{ "while",   RID_WHILE,  0 },
>
> -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> -  { NAME,  RID_##CODE, D_CXXONLY },
> -#include "cp/cp-trait.def"
> -#undef DEFTRAIT
> -  /* An alias for __is_same.  */
> -  { "__is_same_as",RID_IS_SAME,D_CXXONLY },
> -
>/* C++ transactional memory.  */
>{ "synchronized",RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
>{ "atomic_noexcept", RID_ATOMIC_NOEXCEPT, D_CXXONLY | D_TRANSMEM },
> diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> index 1fdba7ef3ea..051a442e0f4 100644
> --- a/gcc/c-family/c-common.h
> +++ b/gcc/c-family/c-common.h
> @@ -168,11 +168,6 @@ enum rid
>RID_BUILTIN_LAUNDER,
>RID_BUILTIN_BIT_CAST,
>
> -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> -  RID_##CODE,
> -#include "cp/cp-trait.def"
> -#undef DEFTRAIT
> -
>/* C++11 */
>RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
>
> diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
> index 93b027b80ce..b1adacfec07 100644
> --- a/gcc/cp/cp-objcp-common.cc
> +++ b/gcc/cp/cp-objcp-common.cc
> @

[PATCH] rust: build failure after NON_DEPENDENT_EXPR removal [PR111899]

2023-10-20 Thread Patrick Palka
Built on x86_64-pc-linux-gnu, pushed to trunk as obvious (hopefully).

-- >8 --

This patch removes stray NON_DEPENDENT_EXPR checks following the removal
of this tree code from the C++ FE.  (Since this restores the build I
supppose it means the Rust FE never creates NON_DEPENDENT_EXPR trees in
the first place, so no further analysis is needed.)

PR rust/111899

gcc/rust/ChangeLog:

* backend/rust-constexpr.cc (potential_constant_expression_1):
Remove NON_DEPENDENT_EXPR handling.
* backend/rust-tree.cc (mark_exp_read): Likewise.
(mark_use): Likewise.
(lvalue_kind): Likewise.
---
 gcc/rust/backend/rust-constexpr.cc | 1 -
 gcc/rust/backend/rust-tree.cc  | 3 ---
 2 files changed, 4 deletions(-)

diff --git a/gcc/rust/backend/rust-constexpr.cc 
b/gcc/rust/backend/rust-constexpr.cc
index b28fa27b2d0..a7ae4166ea0 100644
--- a/gcc/rust/backend/rust-constexpr.cc
+++ b/gcc/rust/backend/rust-constexpr.cc
@@ -6151,7 +6151,6 @@ potential_constant_expression_1 (tree t, bool want_rval, 
bool strict, bool now,
 case CLEANUP_POINT_EXPR:
 case EXPR_STMT:
 case PAREN_EXPR:
-case NON_DEPENDENT_EXPR:
   /* For convenience.  */
 case LOOP_EXPR:
 case EXIT_EXPR:
diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc
index 66e859cd70c..7040c75f825 100644
--- a/gcc/rust/backend/rust-tree.cc
+++ b/gcc/rust/backend/rust-tree.cc
@@ -72,7 +72,6 @@ mark_exp_read (tree exp)
 case ADDR_EXPR:
 case INDIRECT_REF:
 case FLOAT_EXPR:
-case NON_DEPENDENT_EXPR:
 case VIEW_CONVERT_EXPR:
   mark_exp_read (TREE_OPERAND (exp, 0));
   break;
@@ -128,7 +127,6 @@ mark_use (tree expr, bool rvalue_p, bool read_p,
   switch (TREE_CODE (expr))
 {
 case COMPONENT_REF:
-case NON_DEPENDENT_EXPR:
   recurse_op[0] = true;
   break;
 case COMPOUND_EXPR:
@@ -4520,7 +4518,6 @@ lvalue_kind (const_tree ref)
 lvalues.  */
   return (DECL_NONSTATIC_MEMBER_FUNCTION_P (ref) ? clk_none : 
clk_ordinary);
 
-case NON_DEPENDENT_EXPR:
 case PAREN_EXPR:
   return lvalue_kind (TREE_OPERAND (ref, 0));
 
-- 
2.42.0.411.g813d9a9188



[PATCH] rust: build failure after NON_DEPENDENT_EXPR removal [PR111899]

2023-10-20 Thread Patrick Palka
Built on x86_64-pc-linux-gnu, pushed to trunk as obvious (hopefully).

-- >8 --

This patch removes stray NON_DEPENDENT_EXPR checks following the removal
of this tree code from the C++ FE.  (Since this restores the build I
supppose it means the Rust FE never creates NON_DEPENDENT_EXPR trees in
the first place, so no further analysis is needed.)

PR rust/111899

gcc/rust/ChangeLog:

* backend/rust-constexpr.cc (potential_constant_expression_1):
Remove NON_DEPENDENT_EXPR handling.
* backend/rust-tree.cc (mark_exp_read): Likewise.
(mark_use): Likewise.
(lvalue_kind): Likewise.
---
 gcc/rust/backend/rust-constexpr.cc | 1 -
 gcc/rust/backend/rust-tree.cc  | 3 ---
 2 files changed, 4 deletions(-)

diff --git a/gcc/rust/backend/rust-constexpr.cc 
b/gcc/rust/backend/rust-constexpr.cc
index b28fa27b2d0..a7ae4166ea0 100644
--- a/gcc/rust/backend/rust-constexpr.cc
+++ b/gcc/rust/backend/rust-constexpr.cc
@@ -6151,7 +6151,6 @@ potential_constant_expression_1 (tree t, bool want_rval, 
bool strict, bool now,
 case CLEANUP_POINT_EXPR:
 case EXPR_STMT:
 case PAREN_EXPR:
-case NON_DEPENDENT_EXPR:
   /* For convenience.  */
 case LOOP_EXPR:
 case EXIT_EXPR:
diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc
index 66e859cd70c..7040c75f825 100644
--- a/gcc/rust/backend/rust-tree.cc
+++ b/gcc/rust/backend/rust-tree.cc
@@ -72,7 +72,6 @@ mark_exp_read (tree exp)
 case ADDR_EXPR:
 case INDIRECT_REF:
 case FLOAT_EXPR:
-case NON_DEPENDENT_EXPR:
 case VIEW_CONVERT_EXPR:
   mark_exp_read (TREE_OPERAND (exp, 0));
   break;
@@ -128,7 +127,6 @@ mark_use (tree expr, bool rvalue_p, bool read_p,
   switch (TREE_CODE (expr))
 {
 case COMPONENT_REF:
-case NON_DEPENDENT_EXPR:
   recurse_op[0] = true;
   break;
 case COMPOUND_EXPR:
@@ -4520,7 +4518,6 @@ lvalue_kind (const_tree ref)
 lvalues.  */
   return (DECL_NONSTATIC_MEMBER_FUNCTION_P (ref) ? clk_none : 
clk_ordinary);
 
-case NON_DEPENDENT_EXPR:
 case PAREN_EXPR:
   return lvalue_kind (TREE_OPERAND (ref, 0));
 
-- 
2.42.0.411.g813d9a9188



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

2023-10-19 Thread Patrick Palka
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);
  |   ~~^~~

i.e. without the "testcase.C:1:24: note:  " prefix.  Does this look
expected?  (I also wonder if we might want to omit printing the source
code altogether in this case, since we already printed that same line
earlier during the "no matching function" error?)

> 
> 
> Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
> 
> OK for trunk?
> 
> 
> gcc/cp/ChangeLog:
>   * error.cc (print_instantiation_partial_context_line): Call
>   diagnostic_show_locus.
> 
> gcc/testsuite/ChangeLog:
>   * g++.dg/diagnostic/static_assert3.C: Add directives for
>   additional source printing.
>   * g++.dg/template/error60.C: New test.
> 
> Signed-off-by: David Malcolm 
> ---
>  gcc/cp/error.cc   |  2 +
>  .../g++.dg/diagnostic/static_assert3.C|  7 +++-
>  

Re: [PATCH 2/1] c++: more non-static memfn call dependence cleanup [PR106086]

2023-10-19 Thread Patrick Palka
On Thu, 19 Oct 2023, Jason Merrill wrote:

> On 10/12/23 14:49, Patrick Palka wrote:
> > On Tue, 26 Sep 2023, Patrick Palka wrote:
> > 
> > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
> > > for trunk?
> > > 
> > > -- >8 --
> > > 
> > > This follow-up patch removes some more repetition of the type-dependent
> > 
> > On second thought there's no good reason to split these patches into a two
> > part series, so here's a single squashed patch:
> 
> OK.

Thanks.  It turns out this patch slightly depends on the
NON_DEPENDENT_EXPR removal patches, since without them finish_call_expr
in a template context will undesirably do build_non_dependent_expr on
the fn/args before its COMPONENT_REF branch that dispatches to
build_new_method_call, but this latter function expects to be called
with unwrapped fn/args.  This (seemingly latent bug) can trivially be
fixed by moving finish_call_expr's build_non_dependent_expr calls to
happen after the COMPONENT_REF branch, but I reckon I'll just wait until
the NON_DEPENDENT_EXPR removal patches are in before pushing this one.

> 
> > -- >8 --
> > 
> > Subject: [PATCH] c++: non-static memfn call dependence cleanup [PR106086]
> > 
> > In cp_parser_postfix_expression and in the CALL_EXPR case of
> > tsubst_copy_and_build, we essentially repeat the type-dependent and
> > COMPONENT_REF callee cases of finish_call_expr.  This patch deduplicates
> > this logic by making both spots consistently go through finish_call_expr.
> > 
> > This allows us to easily fix PR106086 -- which is about us neglecting to
> > capture 'this' when we resolve a use of a non-static member function of
> > the current instantiation only at lambda regeneration time -- by moving
> > the call to maybe_generic_this_capture from the parser to finish_call_expr
> > so that we consider capturing 'this' at regeneration time as well.
> > 
> > PR c++/106086
> > 
> > gcc/cp/ChangeLog:
> > 
> > * parser.cc (cp_parser_postfix_expression): Consolidate three
> > calls to finish_call_expr, one to build_new_method_call and
> > one to build_min_nt_call_vec into one call to finish_call_expr.
> > Don't call maybe_generic_this_capture here.
> > * pt.cc (tsubst_copy_and_build) : Remove
> > COMPONENT_REF callee handling.
> > (type_dependent_expression_p): Use t_d_object_e_p instead of
> > t_d_e_p for COMPONENT_REF and OFFSET_REF.
> > * semantics.cc (finish_call_expr): In the type-dependent case,
> > call maybe_generic_this_capture here instead.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/template/crash127.C: Expect additional error due to
> > being able to check the member access expression ahead of time.
> > Strengthen the test by not instantiating the class template.
> > * g++.dg/cpp1y/lambda-generic-this5.C: New test.
> > ---
> >   gcc/cp/parser.cc  | 52 +++
> >   gcc/cp/pt.cc  | 27 +-
> >   gcc/cp/semantics.cc   | 12 +++--
> >   .../g++.dg/cpp1y/lambda-generic-this5.C   | 22 
> >   gcc/testsuite/g++.dg/template/crash127.C  |  3 +-
> >   5 files changed, 38 insertions(+), 78 deletions(-)
> >   create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-this5.C
> > 
> > diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> > index f3abae716fe..b00ef36b831 100644
> > --- a/gcc/cp/parser.cc
> > +++ b/gcc/cp/parser.cc
> > @@ -8047,54 +8047,12 @@ cp_parser_postfix_expression (cp_parser *parser,
> > bool address_p, bool cast_p,
> > close_paren_loc);
> > iloc_sentinel ils (combined_loc);
> >   - if (TREE_CODE (postfix_expression) == COMPONENT_REF)
> > - {
> > -   tree instance = TREE_OPERAND (postfix_expression, 0);
> > -   tree fn = TREE_OPERAND (postfix_expression, 1);
> > -
> > -   if (processing_template_decl
> > -   && (type_dependent_object_expression_p (instance)
> > -   || (!BASELINK_P (fn)
> > -   && TREE_CODE (fn) != FIELD_DECL)
> > -   || type_dependent_expression_p (fn)
> > -   || any_type_dependent_arguments_p (args)))
> > - {
> > -   maybe_generic_this_capture (instance, fn);
> > -   postfix_expression
> > - = build_min_nt_call_vec (postfix_expression, arg

Re: [PATCH v3] c++: Fix compile-time-hog in cp_fold_immediate_r [PR111660]

2023-10-19 Thread Patrick Palka
On Tue, 17 Oct 2023, Marek Polacek wrote:

> On Tue, Oct 17, 2023 at 04:49:52PM -0400, Jason Merrill wrote:
> > On 10/16/23 20:39, Marek Polacek wrote:
> > > On Sat, Oct 14, 2023 at 01:13:22AM -0400, Jason Merrill wrote:
> > > > On 10/13/23 14:53, Marek Polacek wrote:
> > > > > On Thu, Oct 12, 2023 at 09:41:43PM -0400, Jason Merrill wrote:
> > > > > > On 10/12/23 17:04, Marek Polacek wrote:
> > > > > > > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> > > > > > > 
> > > > > > > -- >8 --
> > > > > > > My recent patch introducing cp_fold_immediate_r caused exponential
> > > > > > > compile time with nested COND_EXPRs.  The problem is that the 
> > > > > > > COND_EXPR
> > > > > > > case recursively walks the arms of a COND_EXPR, but after 
> > > > > > > processing
> > > > > > > both arms it doesn't end the walk; it proceeds to walk the
> > > > > > > sub-expressions of the outermost COND_EXPR, triggering again 
> > > > > > > walking
> > > > > > > the arms of the nested COND_EXPR, and so on.  This patch brings 
> > > > > > > the
> > > > > > > compile time down to about 0m0.033s.
> > > > > > > 
> > > > > > > I've added some debug prints to make sure that the rest of 
> > > > > > > cp_fold_r
> > > > > > > is still performed as before.
> > > > > > > 
> > > > > > >PR c++/111660
> > > > > > > 
> > > > > > > gcc/cp/ChangeLog:
> > > > > > > 
> > > > > > >* cp-gimplify.cc (cp_fold_immediate_r)  > > > > > > COND_EXPR>: Return
> > > > > > >integer_zero_node instead of break;.
> > > > > > >(cp_fold_immediate): Return true if 
> > > > > > > cp_fold_immediate_r returned
> > > > > > >error_mark_node.
> > > > > > > 
> > > > > > > gcc/testsuite/ChangeLog:
> > > > > > > 
> > > > > > >* g++.dg/cpp0x/hog1.C: New test.
> > > > > > > ---
> > > > > > > gcc/cp/cp-gimplify.cc |  9 ++--
> > > > > > > gcc/testsuite/g++.dg/cpp0x/hog1.C | 77 
> > > > > > > +++
> > > > > > > 2 files changed, 82 insertions(+), 4 deletions(-)
> > > > > > > create mode 100644 gcc/testsuite/g++.dg/cpp0x/hog1.C
> > > > > > > 
> > > > > > > diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
> > > > > > > index bdf6e5f98ff..ca622ca169a 100644
> > > > > > > --- a/gcc/cp/cp-gimplify.cc
> > > > > > > +++ b/gcc/cp/cp-gimplify.cc
> > > > > > > @@ -1063,16 +1063,16 @@ cp_fold_immediate_r (tree *stmt_p, int 
> > > > > > > *walk_subtrees, void *data_)
> > > > > > >   break;
> > > > > > >   if (TREE_OPERAND (stmt, 1)
> > > > > > > && cp_walk_tree (_OPERAND (stmt, 1), 
> > > > > > > cp_fold_immediate_r, data,
> > > > > > > -nullptr))
> > > > > > > +nullptr) == error_mark_node)
> > > > > > >   return error_mark_node;
> > > > > > >   if (TREE_OPERAND (stmt, 2)
> > > > > > > && cp_walk_tree (_OPERAND (stmt, 2), 
> > > > > > > cp_fold_immediate_r, data,
> > > > > > > -nullptr))
> > > > > > > +nullptr) == error_mark_node)
> > > > > > >   return error_mark_node;
> > > > > > >   /* We're done here.  Don't clear *walk_subtrees here 
> > > > > > > though: we're called
> > > > > > >from cp_fold_r and we must let it recurse on the 
> > > > > > > expression with
> > > > > > >cp_fold.  */
> > > > > > > -  break;
> > > > > > > +  return integer_zero_node;
> > > > > > 
> > > > > > I'm concerned this will end up missing something like
> > > > > > 
> > > > > > 1 ? 1 : ((1 ? 1 : 1), immediate())
> > > > > > 
> > > > > > as the integer_zero_node from the inner ?: will prevent walk_tree 
> > > > > > from
> > > > > > looking any farther.
> > > > > 
> > > > > You are right.  The line above works as expected, but
> > > > > 
> > > > > 1 ? 1 : ((1 ? 1 : id (42)), id (i));
> > > > > 
> > > > > shows the problem (when the expression isn't used as an initializer).
> > > > > 
> > > > > > Maybe we want to handle COND_EXPR in cp_fold_r instead of here?
> > > > > 
> > > > > I hope this version is better.
> > > > > 
> > > > > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> > > > > 
> > > > > -- >8 --
> > > > > My recent patch introducing cp_fold_immediate_r caused exponential
> > > > > compile time with nested COND_EXPRs.  The problem is that the 
> > > > > COND_EXPR
> > > > > case recursively walks the arms of a COND_EXPR, but after processing
> > > > > both arms it doesn't end the walk; it proceeds to walk the
> > > > > sub-expressions of the outermost COND_EXPR, triggering again walking
> > > > > the arms of the nested COND_EXPR, and so on.  This patch brings the
> > > > > compile time down to about 0m0.033s.
> > > > 
> > > > Is this number still accurate for this version?
> > > 
> > > It is.  I ran time(1) a few more times and the results were 0m0.033s - 
> > > 0m0.035s.
> > > That said, ...
> > > 
> > > > This change seems algorithmically better than 

Re: [PATCH] c++/modules: ICE with lambda initializing local var [PR105322]

2023-10-18 Thread Patrick Palka
On Wed, 18 Oct 2023, Patrick Palka wrote:

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

Note that this doesn't fix the other testcase in the PR, which doesn't use any
lambdas and which ICEs in the same way:

export module pr105322;

auto f() {
  struct A { int m; };
  return A{};
}

export
inline void g() {
  auto r = decltype(f()){0};
}

Here when streaming the CONSTRUCTOR initializer of r, we end up streaming
components of f()::A before ever streaming the declaration/definition of
f()::A.  I suspect a separate fix might be needed for this testcase?
The narrow fix for the lambda testcase still seems useful nonetheless.

> 
> -- >8 --
> 
> For a local variable initialized by a lambda:
> 
>   auto f = []{};
> 
> The corresponding BLOCK_VARS contains the variable declaration first,
> followed by the closure type declaration, consistent with the
> syntactical order.  This however means that a use of the closure type
> appears (in the variable type/initializer) before the declaration of the
> type.  This ends up causing an ICE when streaming the BLOCK_VARS of f1
> below because we stream (by value) the CONSTRUCTOR initializer of g1 --
> which contains components of the closure type -- before we've streamed
> the declaration defining the closure type.  The following comment in
> module.cc seems relevant:
> 
>   /* We want to stream the type of a expression-like nodes /after/
>  we've streamed the operands.  The type often contains (bits
>  of the) types of the operands, and with things like decltype
>  and noexcept in play, we really want to stream the decls
>  defining the type before we try and stream the type on its
>  own.  Otherwise we can find ourselves trying to read in a
>  decl, when we're already partially reading in a component of
>  its type.  And that's bad.  */
> 
> This patch narrowly fixes this issue by special casing closure type
> declarations in add_decl_to_level.  (A loop is needed since there could
> be multiple variable declarations with an unprocessed initializer in
> light of structured bindings.)
> 
>   PR c++/105322
> 
> gcc/cp/ChangeLog:
> 
>   * name-lookup.cc (add_decl_to_level): When adding a closure
>   type declaration to a block scope, add it before rather than
>   after any variable declarations whose initializer we're still
>   processing.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/modules/lambda-5_a.C: New test.
>   * g++.dg/modules/lambda-5_b.C: New test.
> ---
>  gcc/cp/name-lookup.cc | 19 ---
>  gcc/testsuite/g++.dg/modules/lambda-5_a.C | 23 +++
>  gcc/testsuite/g++.dg/modules/lambda-5_b.C | 10 ++
>  3 files changed, 49 insertions(+), 3 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/modules/lambda-5_a.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/lambda-5_b.C
> 
> diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
> index a8b9229b29e..bb00baaf9f4 100644
> --- a/gcc/cp/name-lookup.cc
> +++ b/gcc/cp/name-lookup.cc
> @@ -391,9 +391,22 @@ add_decl_to_level (cp_binding_level *b, tree decl)
>gcc_assert (b->names != decl);
>  
>/* We build up the list in reverse order, and reverse it later if
> - necessary.  */
> -  TREE_CHAIN (decl) = b->names;
> -  b->names = decl;
> + necessary.  If we're adding a lambda closure type to a block
> + scope as part of a local variable initializer, then make sure
> + we declare the type before the variable; modules expects that
> + we see a type declaration before a use of the type.  */
> +  tree *prev = >names;
> +  if (b->kind == sk_block
> +  && !processing_template_decl
> +  && TREE_CODE (decl) == TYPE_DECL
> +  && LAMBDA_TYPE_P (TREE_TYPE (decl)))
> +while (*prev && VAR_P (*prev)
> +&& !DECL_EXTERNAL (*prev)
> +&& !DECL_INITIALIZED_P (*prev))
> +  prev = _CHAIN (*prev);
> +
> +  TREE_CHAIN (decl) = *prev;
> +  *prev = decl;
>  
>/* If appropriate, add decl to separate list of statics.  We include
>   extern variables because they might turn out to be static later.
> diff --git a/gcc/testsuite/g++.dg/modules/lambda-5_a.C 
> b/gcc/testsuite/g++.dg/modules/lambda-5_a.C
> new file mode 100644
> index 000..6b54c8e3173
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/modules/lambda-5_a.C
> @@ -0,0 +1,23 @@
> +// PR c++/105322
> +// { dg-additional-options -fmodules-ts }
> +// { dg-module-cmi pr105322 }
> +
> +export module pr105322;
> +
> +struct A { };
> +
> +export
> +inline void f

[PATCH] c++/modules: ICE with lambda initializing local var [PR105322]

2023-10-18 Thread Patrick Palka
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?

-- >8 --

For a local variable initialized by a lambda:

  auto f = []{};

The corresponding BLOCK_VARS contains the variable declaration first,
followed by the closure type declaration, consistent with the
syntactical order.  This however means that a use of the closure type
appears (in the variable type/initializer) before the declaration of the
type.  This ends up causing an ICE when streaming the BLOCK_VARS of f1
below because we stream (by value) the CONSTRUCTOR initializer of g1 --
which contains components of the closure type -- before we've streamed
the declaration defining the closure type.  The following comment in
module.cc seems relevant:

  /* We want to stream the type of a expression-like nodes /after/
 we've streamed the operands.  The type often contains (bits
 of the) types of the operands, and with things like decltype
 and noexcept in play, we really want to stream the decls
 defining the type before we try and stream the type on its
 own.  Otherwise we can find ourselves trying to read in a
 decl, when we're already partially reading in a component of
 its type.  And that's bad.  */

This patch narrowly fixes this issue by special casing closure type
declarations in add_decl_to_level.  (A loop is needed since there could
be multiple variable declarations with an unprocessed initializer in
light of structured bindings.)

PR c++/105322

gcc/cp/ChangeLog:

* name-lookup.cc (add_decl_to_level): When adding a closure
type declaration to a block scope, add it before rather than
after any variable declarations whose initializer we're still
processing.

gcc/testsuite/ChangeLog:

* g++.dg/modules/lambda-5_a.C: New test.
* g++.dg/modules/lambda-5_b.C: New test.
---
 gcc/cp/name-lookup.cc | 19 ---
 gcc/testsuite/g++.dg/modules/lambda-5_a.C | 23 +++
 gcc/testsuite/g++.dg/modules/lambda-5_b.C | 10 ++
 3 files changed, 49 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/modules/lambda-5_a.C
 create mode 100644 gcc/testsuite/g++.dg/modules/lambda-5_b.C

diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index a8b9229b29e..bb00baaf9f4 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -391,9 +391,22 @@ add_decl_to_level (cp_binding_level *b, tree decl)
   gcc_assert (b->names != decl);
 
   /* We build up the list in reverse order, and reverse it later if
- necessary.  */
-  TREE_CHAIN (decl) = b->names;
-  b->names = decl;
+ necessary.  If we're adding a lambda closure type to a block
+ scope as part of a local variable initializer, then make sure
+ we declare the type before the variable; modules expects that
+ we see a type declaration before a use of the type.  */
+  tree *prev = >names;
+  if (b->kind == sk_block
+  && !processing_template_decl
+  && TREE_CODE (decl) == TYPE_DECL
+  && LAMBDA_TYPE_P (TREE_TYPE (decl)))
+while (*prev && VAR_P (*prev)
+  && !DECL_EXTERNAL (*prev)
+  && !DECL_INITIALIZED_P (*prev))
+  prev = _CHAIN (*prev);
+
+  TREE_CHAIN (decl) = *prev;
+  *prev = decl;
 
   /* If appropriate, add decl to separate list of statics.  We include
  extern variables because they might turn out to be static later.
diff --git a/gcc/testsuite/g++.dg/modules/lambda-5_a.C 
b/gcc/testsuite/g++.dg/modules/lambda-5_a.C
new file mode 100644
index 000..6b54c8e3173
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/lambda-5_a.C
@@ -0,0 +1,23 @@
+// PR c++/105322
+// { dg-additional-options -fmodules-ts }
+// { dg-module-cmi pr105322 }
+
+export module pr105322;
+
+struct A { };
+
+export
+inline void f1() {
+  A a;
+  auto g1 = [a] { }; // used to ICE here during stream out
+}
+
+export
+template
+void f2() {
+  A a;
+  auto g2 = [a] { };
+}
+
+export
+inline auto g3 = [a=A{}] { };
diff --git a/gcc/testsuite/g++.dg/modules/lambda-5_b.C 
b/gcc/testsuite/g++.dg/modules/lambda-5_b.C
new file mode 100644
index 000..e25a913b726
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/lambda-5_b.C
@@ -0,0 +1,10 @@
+// PR c++/105322
+// { dg-additional-options -fmodules-ts }
+
+import pr105322;
+
+int main() {
+  f1();
+  f2();
+  g3();
+}
-- 
2.42.0.398.ga9ecda2788



Re: [PATCH v22 02/31] c-family, c++: Look up built-in traits via identifier node

2023-10-17 Thread Patrick Palka
On Tue, 17 Oct 2023, Ken Matsui wrote:

> Since RID_MAX soon reaches 255 and all built-in traits are used approximately
> once in a C++ translation unit, this patch removes all RID values for built-in
> traits and uses the identifier node to look up the specific trait.  Rather
> than holding traits as keywords, we set all trait identifiers as cik_trait,
> which is a new cp_identifier_kind.  As cik_reserved_for_udlit was unused and
> cp_identifier_kind is 3 bits, we replaced the unused field with the new
> cik_trait.  Also, the later patch handles a subsequent token to the built-in
> identifier so that we accept the use of non-function-like built-in trait
> identifiers.
> 
> gcc/c-family/ChangeLog:
> 
>   * c-common.cc (c_common_reswords): Remove all mappings of
>   built-in traits.
>   * c-common.h (enum rid): Remove all RID values for built-in traits.
> 
> gcc/cp/ChangeLog:
> 
>   * cp-objcp-common.cc (names_builtin_p): Remove all RID value
>   cases for built-in traits.  Check for built-in traits via
>   the new cik_trait kind.
>   * cp-tree.h (enum cp_trait_kind): Set its underlying type to
>   addr_space_t.
>   (struct cp_trait): New struct to hold trait information.
>   (cp_traits): New array to hold a mapping to all traits.
>   (num_cp_traits): New variable to hold the size of cp_traits.
>   (cik_reserved_for_udlit): Rename to ...
>   (cik_trait): ... this.
>   (IDENTIFIER_ANY_OP_P): Exclude cik_trait.
>   (IDENTIFIER_TRAIT_P): New macro to detect cik_trait.
>   * lex.cc (init_cp_traits): New function to set cik_trait and
>   IDENTIFIER_CP_INDEX for all built-in trait identifiers.
>   (cxx_init): Call init_cp_traits function.
>   * parser.cc (cp_traits): Define its values, declared in cp-tree.h.
>   (num_cp_traits): Define its value, declared in cp-tree.h.
>   (cp_lexer_lookup_trait): New function to look up a
>   built-in trait by IDENTIFIER_CP_INDEX.
>   (cp_lexer_lookup_trait_expr): Likewise, look up an
>   expression-yielding built-in trait.
>   (cp_lexer_lookup_trait_type): Likewise, look up a type-yielding
>   built-in trait.
>   (cp_keyword_starts_decl_specifier_p): Remove all RID value cases
>   for built-in traits.
>   (cp_lexer_next_token_is_decl_specifier_keyword): Handle
>   type-yielding built-in traits.
>   (cp_parser_primary_expression): Remove all RID value cases for
>   built-in traits.  Handle expression-yielding built-in traits.
>   (cp_parser_trait): Handle cp_trait instead of enum rid.
>   (cp_parser_simple_type_specifier): Remove all RID value cases
>   for built-in traits.  Handle type-yielding built-in traits.
> 
> Co-authored-by: Patrick Palka 
> Signed-off-by: Ken Matsui 
> ---
>  gcc/c-family/c-common.cc  |   7 ---
>  gcc/c-family/c-common.h   |   5 --
>  gcc/cp/cp-objcp-common.cc |   8 +--
>  gcc/cp/cp-tree.h  |  33 ---
>  gcc/cp/lex.cc |  21 +++
>  gcc/cp/parser.cc  | 120 +-
>  6 files changed, 129 insertions(+), 65 deletions(-)
> 
> diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
> index f044db5b797..21fd333ef57 100644
> --- a/gcc/c-family/c-common.cc
> +++ b/gcc/c-family/c-common.cc
> @@ -508,13 +508,6 @@ const struct c_common_resword c_common_reswords[] =
>{ "wchar_t",   RID_WCHAR,  D_CXXONLY },
>{ "while", RID_WHILE,  0 },
>  
> -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> -  { NAME,RID_##CODE, D_CXXONLY },
> -#include "cp/cp-trait.def"
> -#undef DEFTRAIT
> -  /* An alias for __is_same.  */
> -  { "__is_same_as",  RID_IS_SAME,D_CXXONLY },
> -
>/* C++ transactional memory.  */
>{ "synchronized",  RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
>{ "atomic_noexcept",   RID_ATOMIC_NOEXCEPT, D_CXXONLY | D_TRANSMEM },
> diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> index 1fdba7ef3ea..051a442e0f4 100644
> --- a/gcc/c-family/c-common.h
> +++ b/gcc/c-family/c-common.h
> @@ -168,11 +168,6 @@ enum rid
>RID_BUILTIN_LAUNDER,
>RID_BUILTIN_BIT_CAST,
>  
> -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> -  RID_##CODE,
> -#include "cp/cp-trait.def"
> -#undef DEFTRAIT
> -
>/* C++11 */
>RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
>  
> diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
> index 93b027b80ce..b1adacfec07 100644
> --- a/gcc/cp/cp-objcp-common.cc
> +++ b/gcc/cp/cp-objcp-common.cc
> @@ -421,6 +421,10 @@ names_builtin_p (co

Re: [PATCH v20 01/40] c++: Sort built-in traits alphabetically

2023-10-16 Thread Patrick Palka
On Mon, 16 Oct 2023, Ken Matsui wrote:

> On Mon, Oct 16, 2023 at 8:17 AM Patrick Palka  wrote:
> >
> > On Sun, 15 Oct 2023, Ken Matsui wrote:
> >
> > > This patch sorts built-in traits alphabetically for better code
> > > readability.
> >
> > Hmm, I'm not sure if we still want/need this change with this current
> > approach.  IIUC gperf would sort the trait names when generating the
> > hash table code, and so we wanted a more consistent mapping from the
> > cp-trait.def file to the generated code.  But with this current
> > non-gperf approach I'm inclined to leave the existing ordering alone
> > for sake of simplicity, and I kind of like that in cp-trait.def we
> > currently group all expression-yielding traits together and all
> > type-yielding traits together; that seems like a more natural layout
> > than plain alphabetical sorting.
> >
> 
> I see. But this patch is crucial for me to keep all my existing
> patches almost conflict-free against rebase, including drop, add, and
> edit like you suggested to split integral-related patches. Without
> this patch and alphabetical order, I will need to put a new trait in a
> random place not close to surrounding commits, as Git relates close
> lines when it finds conflicts. When I merged all my patches into one
> patch series, I needed to fix conflicts for all my patches almost
> every time I rebased. Both thinking of the random place and fixing the
> conflicts of all patches would definitely not be desirable. Would you
> think we should drop this patch?

Fair enough, I'm all for keeping this patch and alphabetizing then :)

> 
> > >
> > > gcc/cp/ChangeLog:
> > >
> > >   * constraint.cc (diagnose_trait_expr): Sort built-in traits
> > >   alphabetically.
> > >   * cp-trait.def: Likewise.
> > >   * semantics.cc (trait_expr_value): Likewise.
> > >   (finish_trait_expr): Likewise.
> > >   (finish_trait_type): Likewise.
> > >
> > > gcc/testsuite/ChangeLog:
> > >
> > >   * g++.dg/ext/has-builtin-1.C: Sort built-in traits alphabetically.
> > >
> > > Signed-off-by: Ken Matsui 
> > > ---
> > >  gcc/cp/constraint.cc | 68 -
> > >  gcc/cp/cp-trait.def  | 10 +--
> > >  gcc/cp/semantics.cc  | 94 
> > >  gcc/testsuite/g++.dg/ext/has-builtin-1.C | 70 +-
> > >  4 files changed, 121 insertions(+), 121 deletions(-)
> > >
> > > diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> > > index c9e4e7043cd..722fc334e6f 100644
> > > --- a/gcc/cp/constraint.cc
> > > +++ b/gcc/cp/constraint.cc
> > > @@ -3702,18 +3702,36 @@ diagnose_trait_expr (tree expr, tree args)
> > >  case CPTK_HAS_TRIVIAL_DESTRUCTOR:
> > >inform (loc, "  %qT is not trivially destructible", t1);
> > >break;
> > > +case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
> > > +  inform (loc, "  %qT does not have unique object representations", 
> > > t1);
> > > +  break;
> > >  case CPTK_HAS_VIRTUAL_DESTRUCTOR:
> > >inform (loc, "  %qT does not have a virtual destructor", t1);
> > >break;
> > >  case CPTK_IS_ABSTRACT:
> > >inform (loc, "  %qT is not an abstract class", t1);
> > >break;
> > > +case CPTK_IS_AGGREGATE:
> > > +  inform (loc, "  %qT is not an aggregate", t1);
> > > +  break;
> > > +case CPTK_IS_ASSIGNABLE:
> > > +  inform (loc, "  %qT is not assignable from %qT", t1, t2);
> > > +  break;
> > >  case CPTK_IS_BASE_OF:
> > >inform (loc, "  %qT is not a base of %qT", t1, t2);
> > >break;
> > >  case CPTK_IS_CLASS:
> > >inform (loc, "  %qT is not a class", t1);
> > >break;
> > > +case CPTK_IS_CONSTRUCTIBLE:
> > > +  if (!t2)
> > > +inform (loc, "  %qT is not default constructible", t1);
> > > +  else
> > > +inform (loc, "  %qT is not constructible from %qE", t1, t2);
> > > +  break;
> > > +case CPTK_IS_CONVERTIBLE:
> > > +  inform (loc, "  %qT is not convertible from %qE", t2, t1);
> > > +  break;
> > >  case CPTK_IS_EMPTY:
> > >inform (loc, "  %qT is not an empty class"

Re: [PATCH v20 02/40] c-family, c++: Look up built-in traits via identifier node

2023-10-16 Thread Patrick Palka
On Mon, 16 Oct 2023, Ken Matsui wrote:

> On Mon, Oct 16, 2023 at 7:55 AM Patrick Palka  wrote:
> >
> > On Sun, 15 Oct 2023, Ken Matsui wrote:
> >
> > > Since RID_MAX soon reaches 255 and all built-in traits are used 
> > > approximately
> > > once in a C++ translation unit, this patch removes all RID values for 
> > > built-in
> > > traits and uses the identifier node to look up the specific trait.  Rather
> > > than holding traits as keywords, we set all trait identifiers as 
> > > cik_trait,
> > > which is a new cp_identifier_kind.  As cik_reserved_for_udlit was unused 
> > > and
> > > cp_identifier_kind is 3 bits, we replaced the unused field with the new
> > > cik_trait.  Also, the later patch handles a subsequent token to the 
> > > built-in
> > > identifier so that we accept the use of non-function-like built-in trait
> > > identifiers.
> >
> > Thanks, this looks great!  Some review comments below.
> >
> 
> Thank you so much for your review :)
> 
> > >
> > > gcc/c-family/ChangeLog:
> > >
> > >   * c-common.cc (c_common_reswords): Remove all mappings of
> > >   built-in traits.
> > >   * c-common.h (enum rid): Remove all RID values for built-in traits.
> > >
> > > gcc/cp/ChangeLog:
> > >
> > >   * cp-objcp-common.cc (names_builtin_p): Remove all RID value
> > >   cases for built-in traits.  Check for built-in traits via
> > >   the new cik_trait kind.
> > >   * cp-tree.h (enum cp_trait_kind): Set its underlying type to
> > >   addr_space_t.
> > >   (struct cp_trait): New struct to hold trait information.
> > >   (cp_traits): New array to hold a mapping to all traits.
> > >   (cik_reserved_for_udlit): Rename to ...
> > >   (cik_trait): ... this.
> > >   (IDENTIFIER_ANY_OP_P): Exclude cik_trait.
> > >   (IDENTIFIER_TRAIT_P): New macro to detect cik_trait.
> > >   * lex.cc (init_cp_traits): New function to set cik_trait for all
> > >   built-in trait identifiers.
> >
> > We should mention setting IDENTIFIER_CP_INDEX as well.
> >
> 
> Thank you!
> 
> > >   (cxx_init): Call init_cp_traits function.
> > >   * parser.cc (cp_traits): Define its values, declared in cp-tree.h.
> > >   (cp_lexer_lookup_trait): New function to look up a
> > >   built-in trait by IDENTIFIER_CP_INDEX.
> > >   (cp_lexer_lookup_trait_expr): Likewise, look up an
> > >   expression-yielding built-in trait.
> > >   (cp_lexer_lookup_trait_type): Likewise, look up a type-yielding
> > >   built-in trait.
> > >   (cp_keyword_starts_decl_specifier_p): Remove all RID value cases
> > >   for built-in traits.
> > >   (cp_lexer_next_token_is_decl_specifier_keyword): Handle
> > >   type-yielding built-in traits.
> > >   (cp_parser_primary_expression): Remove all RID value cases for
> > >   built-in traits.  Handle expression-yielding built-in traits.
> > >   (cp_parser_trait): Handle cp_trait instead of enum rid.
> > >   (cp_parser_simple_type_specifier): Remove all RID value cases
> > >   for built-in traits.  Handle type-yielding built-in traits.
> > >
> > > Co-authored-by: Patrick Palka 
> > > Signed-off-by: Ken Matsui 
> > > ---
> > >  gcc/c-family/c-common.cc  |   7 --
> > >  gcc/c-family/c-common.h   |   5 --
> > >  gcc/cp/cp-objcp-common.cc |   8 +--
> > >  gcc/cp/cp-tree.h  |  31 ++---
> > >  gcc/cp/lex.cc |  21 ++
> > >  gcc/cp/parser.cc  | 141 --
> > >  6 files changed, 139 insertions(+), 74 deletions(-)
> > >
> > > diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
> > > index f044db5b797..21fd333ef57 100644
> > > --- a/gcc/c-family/c-common.cc
> > > +++ b/gcc/c-family/c-common.cc
> > > @@ -508,13 +508,6 @@ const struct c_common_resword c_common_reswords[] =
> > >{ "wchar_t",   RID_WCHAR,  D_CXXONLY },
> > >{ "while", RID_WHILE,  0 },
> > >
> > > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > > -  { NAME,RID_##CODE, D_CXXONLY },
> > > -#include "cp/cp-trait.def"
> > > -#undef DEFTRAIT
> > > -  /* An alias for __is_same.  */
> > > -  { "__is_same_as",  RID_

Re: [PATCH v20 26/40] libstdc++: Optimize is_object trait performance

2023-10-16 Thread Patrick Palka
On Sun, 15 Oct 2023, Ken Matsui wrote:

> This patch optimizes the performance of the is_object trait by dispatching to
> the new __is_function and __is_reference built-in traits.
> 
> libstdc++-v3/ChangeLog:
>   * include/std/type_traits (is_object): Use __is_function and
>   __is_reference built-in traits.
>   (is_object_v): Likewise.
> 
> Signed-off-by: Ken Matsui 
> ---
>  libstdc++-v3/include/std/type_traits | 18 ++
>  1 file changed, 18 insertions(+)
> 
> diff --git a/libstdc++-v3/include/std/type_traits 
> b/libstdc++-v3/include/std/type_traits
> index bd57488824b..674d398c075 100644
> --- a/libstdc++-v3/include/std/type_traits
> +++ b/libstdc++-v3/include/std/type_traits
> @@ -725,11 +725,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>  { };
>  
>/// is_object
> +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
> + && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
> +  template
> +struct is_object
> +: public __bool_constant + || is_void<_Tp>::value)>
> +{ };

Since is_object is one of the more commonly used traits, we should
probably just define a built-in for it.  (Either way we'd have to
repeat the logic twice, either once in the frontend and once in
the library, or twice in the library (is_object and is_object_v),
so might as well do the more efficient approach).

> +#else
>template
>  struct is_object
>  : public __not_<__or_, is_reference<_Tp>,
>is_void<_Tp>>>::type
>  { };
> +#endif
>  
>template
>  struct is_member_pointer;
> @@ -3305,8 +3314,17 @@ template 
>inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
>  template 
>inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
> +
> +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
> + && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
> +template 
> +  inline constexpr bool is_object_v
> += !(__is_function(_Tp) || __is_reference(_Tp) || is_void<_Tp>::value);
> +#else
>  template 
>inline constexpr bool is_object_v = is_object<_Tp>::value;
> +#endif
> +
>  template 
>inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
>  template 
> -- 
> 2.42.0
> 
> 



Re: [PATCH v20 31/40] c++: Implement __is_arithmetic built-in trait

2023-10-16 Thread Patrick Palka
On Sun, 15 Oct 2023, Ken Matsui wrote:

> This patch implements built-in trait for std::is_arithmetic.
> 
> gcc/cp/ChangeLog:
> 
>   * cp-trait.def: Define __is_arithmetic.
>   * constraint.cc (diagnose_trait_expr): Handle CPTK_IS_ARITHMETIC.
>   * semantics.cc (trait_expr_value): Likewise.
>   (finish_trait_expr): Likewise.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/ext/has-builtin-1.C: Test existence of __is_arithmetic.
>   * g++.dg/ext/is_arithmetic.C: New test.
> 
> Signed-off-by: Ken Matsui 
> ---
>  gcc/cp/constraint.cc |  3 +++
>  gcc/cp/cp-trait.def  |  1 +
>  gcc/cp/semantics.cc  |  4 +++
>  gcc/testsuite/g++.dg/ext/has-builtin-1.C |  3 +++
>  gcc/testsuite/g++.dg/ext/is_arithmetic.C | 33 
>  5 files changed, 44 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_arithmetic.C
> 
> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> index c9d627fa782..3a7f968eae8 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -3714,6 +3714,9 @@ diagnose_trait_expr (tree expr, tree args)
>  case CPTK_IS_AGGREGATE:
>inform (loc, "  %qT is not an aggregate", t1);
>break;
> +case CPTK_IS_ARITHMETIC:
> +  inform (loc, "  %qT is not an arithmetic type", t1);
> +  break;
>  case CPTK_IS_ARRAY:
>inform (loc, "  %qT is not an array", t1);
>break;
> diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
> index c60724e869e..b2be7b7bbd7 100644
> --- a/gcc/cp/cp-trait.def
> +++ b/gcc/cp/cp-trait.def
> @@ -59,6 +59,7 @@ DEFTRAIT_EXPR (HAS_UNIQUE_OBJ_REPRESENTATIONS, 
> "__has_unique_object_representati
>  DEFTRAIT_EXPR (HAS_VIRTUAL_DESTRUCTOR, "__has_virtual_destructor", 1)
>  DEFTRAIT_EXPR (IS_ABSTRACT, "__is_abstract", 1)
>  DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
> +DEFTRAIT_EXPR (IS_ARITHMETIC, "__is_arithmetic", 1)
>  DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
>  DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
>  DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index 83ed674b9d4..deab0134509 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -12143,6 +12143,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, 
> tree type2)
>  case CPTK_IS_AGGREGATE:
>return CP_AGGREGATE_TYPE_P (type1);
>  
> +case CPTK_IS_ARITHMETIC:
> +  return ARITHMETIC_TYPE_P (type1);
> +

For built-ins corresponding to is_arithmetic and other standard traits
defined in terms of it (e.g.  is_scalar, is_unsigned, is_signed,
is_fundamental) we need to make sure we preserve their behavior for
__int128, which IIUC is currently recognized as an integral type
(according to std::is_integral) only in GNU mode.

This'll probably be subtle to get right, so if you don't mind let's
split out the work for those built-in traits into a separate patch
series in order to ease review of the main patch series.

>  case CPTK_IS_ARRAY:
>return type_code1 == ARRAY_TYPE;
>  
> @@ -12406,6 +12409,7 @@ finish_trait_expr (location_t loc, cp_trait_kind 
> kind, tree type1, tree type2)
>   return error_mark_node;
>break;
>  
> +case CPTK_IS_ARITHMETIC:
>  case CPTK_IS_ARRAY:
>  case CPTK_IS_BOUNDED_ARRAY:
>  case CPTK_IS_CLASS:
> diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C 
> b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> index efce04fd09d..4bc85f4babb 100644
> --- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> +++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> @@ -56,6 +56,9 @@
>  #if !__has_builtin (__is_aggregate)
>  # error "__has_builtin (__is_aggregate) failed"
>  #endif
> +#if !__has_builtin (__is_arithmetic)
> +# error "__has_builtin (__is_arithmetic) failed"
> +#endif
>  #if !__has_builtin (__is_array)
>  # error "__has_builtin (__is_array) failed"
>  #endif
> diff --git a/gcc/testsuite/g++.dg/ext/is_arithmetic.C 
> b/gcc/testsuite/g++.dg/ext/is_arithmetic.C
> new file mode 100644
> index 000..fd35831f646
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/ext/is_arithmetic.C
> @@ -0,0 +1,33 @@
> +// { dg-do compile { target c++11 } }
> +
> +#include 
> +
> +using namespace __gnu_test;
> +
> +#define SA(X) static_assert((X),#X)
> +#define SA_TEST_CATEGORY(TRAIT, TYPE, EXPECT)\
> +  SA(TRAIT(TYPE) == EXPECT); \
> +  SA(TRAIT(const TYPE) == EXPECT);   \
> +  SA(TRAIT(volatile TYPE) == EXPECT);\
> +  SA(TRAIT(const volatile TYPE) == EXPECT)
> +
> +SA_TEST_CATEGORY(__is_arithmetic, void, false);
> +
> +SA_TEST_CATEGORY(__is_arithmetic, char, true);
> +SA_TEST_CATEGORY(__is_arithmetic, signed char, true);
> +SA_TEST_CATEGORY(__is_arithmetic, unsigned char, true);
> +SA_TEST_CATEGORY(__is_arithmetic, wchar_t, true);
> +SA_TEST_CATEGORY(__is_arithmetic, short, true);
> +SA_TEST_CATEGORY(__is_arithmetic, unsigned short, true);
> 

Re: [PATCH v20 30/40] libstdc++: Optimize is_pointer trait performance

2023-10-16 Thread Patrick Palka
On Sun, 15 Oct 2023, Ken Matsui wrote:

> This patch optimizes the performance of the is_pointer trait by dispatching to
> the new __is_pointer built-in trait.
> 
> libstdc++-v3/ChangeLog:
> 
>   * include/bits/cpp_type_traits.h (__is_pointer): Use __is_pointer
>   built-in trait.
>   * include/std/type_traits (is_pointer): Likewise. Optimize its
>   implementation.
>   (is_pointer_v): Likewise.
> 
> Co-authored-by: Jonathan Wakely 
> Signed-off-by: Ken Matsui 
> ---
>  libstdc++-v3/include/bits/cpp_type_traits.h |  8 
>  libstdc++-v3/include/std/type_traits| 44 +
>  2 files changed, 44 insertions(+), 8 deletions(-)
> 
> diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h 
> b/libstdc++-v3/include/bits/cpp_type_traits.h
> index 4312f32a4e0..cd5ce45951f 100644
> --- a/libstdc++-v3/include/bits/cpp_type_traits.h
> +++ b/libstdc++-v3/include/bits/cpp_type_traits.h
> @@ -363,6 +363,13 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
>//
>// Pointer types
>//
> +#if __has_builtin(__is_pointer)

Why not _GLIBCXX_USE_BUILTIN_TRAIT?  LGTM besides this.

> +  template
> +struct __is_pointer : __truth_type<__is_pointer(_Tp)>
> +{
> +  enum { __value = __is_pointer(_Tp) };
> +};

Nice :D

> +#else
>template
>  struct __is_pointer
>  {
> @@ -376,6 +383,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
>enum { __value = 1 };
>typedef __true_type __type;
>  };
> +#endif
>  
>//
>// An arithmetic type is an integer type or a floating point type
> diff --git a/libstdc++-v3/include/std/type_traits 
> b/libstdc++-v3/include/std/type_traits
> index 9c56d15c0b7..3acd843f2f2 100644
> --- a/libstdc++-v3/include/std/type_traits
> +++ b/libstdc++-v3/include/std/type_traits
> @@ -542,19 +542,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>  : public true_type { };
>  #endif
>  
> -  template
> -struct __is_pointer_helper
> +  /// is_pointer
> +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
> +  template
> +struct is_pointer
> +: public __bool_constant<__is_pointer(_Tp)>
> +{ };
> +#else
> +  template
> +struct is_pointer
>  : public false_type { };
>  
>template
> -struct __is_pointer_helper<_Tp*>
> +struct is_pointer<_Tp*>
>  : public true_type { };
>  
> -  /// is_pointer
>template
> -struct is_pointer
> -: public __is_pointer_helper<__remove_cv_t<_Tp>>::type
> -{ };
> +struct is_pointer<_Tp* const>
> +: public true_type { };
> +
> +  template
> +struct is_pointer<_Tp* volatile>
> +: public true_type { };
> +
> +  template
> +struct is_pointer<_Tp* const volatile>
> +: public true_type { };
> +#endif
>  
>/// is_lvalue_reference
>template
> @@ -3254,8 +3268,22 @@ template 
>inline constexpr bool is_array_v<_Tp[_Num]> = true;
>  #endif
>  
> +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
> +template 
> +  inline constexpr bool is_pointer_v = __is_pointer(_Tp);
> +#else
>  template 
> -  inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
> +  inline constexpr bool is_pointer_v = false;
> +template 
> +  inline constexpr bool is_pointer_v<_Tp*> = true;
> +template 
> +  inline constexpr bool is_pointer_v<_Tp* const> = true;
> +template 
> +  inline constexpr bool is_pointer_v<_Tp* volatile> = true;
> +template 
> +  inline constexpr bool is_pointer_v<_Tp* const volatile> = true;
> +#endif
> +
>  template 
>inline constexpr bool is_lvalue_reference_v = false;
>  template 
> -- 
> 2.42.0
> 
> 



Re: [PATCH v20 01/40] c++: Sort built-in traits alphabetically

2023-10-16 Thread Patrick Palka
On Sun, 15 Oct 2023, Ken Matsui wrote:

> This patch sorts built-in traits alphabetically for better code
> readability.

Hmm, I'm not sure if we still want/need this change with this current
approach.  IIUC gperf would sort the trait names when generating the
hash table code, and so we wanted a more consistent mapping from the
cp-trait.def file to the generated code.  But with this current
non-gperf approach I'm inclined to leave the existing ordering alone
for sake of simplicity, and I kind of like that in cp-trait.def we
currently group all expression-yielding traits together and all
type-yielding traits together; that seems like a more natural layout
than plain alphabetical sorting.

> 
> gcc/cp/ChangeLog:
> 
>   * constraint.cc (diagnose_trait_expr): Sort built-in traits
>   alphabetically.
>   * cp-trait.def: Likewise.
>   * semantics.cc (trait_expr_value): Likewise.
>   (finish_trait_expr): Likewise.
>   (finish_trait_type): Likewise.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/ext/has-builtin-1.C: Sort built-in traits alphabetically.
> 
> Signed-off-by: Ken Matsui 
> ---
>  gcc/cp/constraint.cc | 68 -
>  gcc/cp/cp-trait.def  | 10 +--
>  gcc/cp/semantics.cc  | 94 
>  gcc/testsuite/g++.dg/ext/has-builtin-1.C | 70 +-
>  4 files changed, 121 insertions(+), 121 deletions(-)
> 
> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> index c9e4e7043cd..722fc334e6f 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -3702,18 +3702,36 @@ diagnose_trait_expr (tree expr, tree args)
>  case CPTK_HAS_TRIVIAL_DESTRUCTOR:
>inform (loc, "  %qT is not trivially destructible", t1);
>break;
> +case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
> +  inform (loc, "  %qT does not have unique object representations", t1);
> +  break;
>  case CPTK_HAS_VIRTUAL_DESTRUCTOR:
>inform (loc, "  %qT does not have a virtual destructor", t1);
>break;
>  case CPTK_IS_ABSTRACT:
>inform (loc, "  %qT is not an abstract class", t1);
>break;
> +case CPTK_IS_AGGREGATE:
> +  inform (loc, "  %qT is not an aggregate", t1);
> +  break;
> +case CPTK_IS_ASSIGNABLE:
> +  inform (loc, "  %qT is not assignable from %qT", t1, t2);
> +  break;
>  case CPTK_IS_BASE_OF:
>inform (loc, "  %qT is not a base of %qT", t1, t2);
>break;
>  case CPTK_IS_CLASS:
>inform (loc, "  %qT is not a class", t1);
>break;
> +case CPTK_IS_CONSTRUCTIBLE:
> +  if (!t2)
> +inform (loc, "  %qT is not default constructible", t1);
> +  else
> +inform (loc, "  %qT is not constructible from %qE", t1, t2);
> +  break;
> +case CPTK_IS_CONVERTIBLE:
> +  inform (loc, "  %qT is not convertible from %qE", t2, t1);
> +  break;
>  case CPTK_IS_EMPTY:
>inform (loc, "  %qT is not an empty class", t1);
>break;
> @@ -3729,6 +3747,18 @@ diagnose_trait_expr (tree expr, tree args)
>  case CPTK_IS_LITERAL_TYPE:
>inform (loc, "  %qT is not a literal type", t1);
>break;
> +case CPTK_IS_NOTHROW_ASSIGNABLE:
> +  inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
> +  break;
> +case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
> +  if (!t2)
> + inform (loc, "  %qT is not nothrow default constructible", t1);
> +  else
> + inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
> +  break;
> +case CPTK_IS_NOTHROW_CONVERTIBLE:
> +   inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
> +  break;
>  case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
>inform (loc, "  %qT is not pointer-interconvertible base of %qT",
> t1, t2);
> @@ -3748,50 +3778,20 @@ diagnose_trait_expr (tree expr, tree args)
>  case CPTK_IS_TRIVIAL:
>inform (loc, "  %qT is not a trivial type", t1);
>break;
> -case CPTK_IS_UNION:
> -  inform (loc, "  %qT is not a union", t1);
> -  break;
> -case CPTK_IS_AGGREGATE:
> -  inform (loc, "  %qT is not an aggregate", t1);
> -  break;
> -case CPTK_IS_TRIVIALLY_COPYABLE:
> -  inform (loc, "  %qT is not trivially copyable", t1);
> -  break;
> -case CPTK_IS_ASSIGNABLE:
> -  inform (loc, "  %qT is not assignable from %qT", t1, t2);
> -  break;
>  case CPTK_IS_TRIVIALLY_ASSIGNABLE:
>inform (loc, "  %qT is not trivially assignable from %qT", t1, t2);
>break;
> -case CPTK_IS_NOTHROW_ASSIGNABLE:
> -  inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
> -  break;
> -case CPTK_IS_CONSTRUCTIBLE:
> -  if (!t2)
> - inform (loc, "  %qT is not default constructible", t1);
> -  else
> - inform (loc, "  %qT is not constructible from %qE", t1, t2);
> -  break;
>  case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
>

Re: [PATCH v20 03/40] c++: Accept the use of built-in trait identifiers

2023-10-16 Thread Patrick Palka
On Sun, 15 Oct 2023, Ken Matsui wrote:

> This patch accepts the use of built-in trait identifiers when they are
> actually not used as traits.  Specifically, we check if the subsequent token
> is '(' for ordinary built-in traits or is '<' only for the special
> __type_pack_element built-in trait.  If those identifiers are used
> differently, the parser treats them as normal identifiers.  This allows
> us to accept code like: struct __is_pointer {};.

LGTM, thanks

> 
> gcc/cp/ChangeLog:
> 
>   * parser.cc (cp_lexer_lookup_trait): Rename to ...
>   (cp_lexer_peek_trait): ... this.  Handle a subsequent token for
>   the corresponding built-in trait.
>   (cp_lexer_lookup_trait_expr): Rename to ...
>   (cp_lexer_peek_trait_expr): ... this.
>   (cp_lexer_lookup_trait_type): Rename to ...
>   (cp_lexer_peek_trait_type): ... this.
>   (cp_lexer_next_token_is_decl_specifier_keyword): Call
>   cp_lexer_peek_trait_type.
>   (cp_parser_simple_type_specifier): Likewise.
>   (cp_parser_primary_expression): Call cp_lexer_peek_trait_expr.
> 
> Signed-off-by: Ken Matsui 
> ---
>  gcc/cp/parser.cc | 48 ++--
>  1 file changed, 30 insertions(+), 18 deletions(-)
> 
> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> index eba5272be03..0f2a1baee6a 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -246,12 +246,12 @@ static void cp_lexer_start_debugging
>(cp_lexer *) ATTRIBUTE_UNUSED;
>  static void cp_lexer_stop_debugging
>(cp_lexer *) ATTRIBUTE_UNUSED;
> -static const cp_trait *cp_lexer_lookup_trait
> -  (const cp_token *);
> -static const cp_trait *cp_lexer_lookup_trait_expr
> -  (const cp_token *);
> -static const cp_trait *cp_lexer_lookup_trait_type
> -  (const cp_token *);
> +static const cp_trait *cp_lexer_peek_trait
> +  (cp_lexer *lexer, const cp_token *);
> +static const cp_trait *cp_lexer_peek_trait_expr
> +  (cp_lexer *lexer, const cp_token *);
> +static const cp_trait *cp_lexer_peek_trait_type
> +  (cp_lexer *lexer, const cp_token *);
>  
>  static cp_token_cache *cp_token_cache_new
>(cp_token *, cp_token *);
> @@ -1195,19 +1195,31 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
>  }
>  }
>  
> -/* Look ups the corresponding built-in trait if a given token is
> +/* Peeks the corresponding built-in trait if a given token is
> a built-in trait.  Otherwise, returns nullptr.  */
>  
>  static const cp_trait *
> -cp_lexer_lookup_trait (const cp_token *token)
> +cp_lexer_peek_trait (cp_lexer *lexer, const cp_token *token1)
>  {
> -  tree id = token->u.value;
> +  tree id = token1->u.value;
>  
> -  if (token->type == CPP_NAME
> +  if (token1->type == CPP_NAME
>&& TREE_CODE (id) == IDENTIFIER_NODE
>&& IDENTIFIER_TRAIT_P (id))
> -return _traits[IDENTIFIER_CP_INDEX (id)];
> +{
> +  const cp_trait  = cp_traits[IDENTIFIER_CP_INDEX (id)];
> +  const bool is_pack_element = (trait.kind == CPTK_TYPE_PACK_ELEMENT);
>  
> +  /* Check if the subsequent token is a `<' token to
> + __type_pack_element or is a `(' token to everything else.  */
> +  const cp_token *token2 = cp_lexer_peek_nth_token (lexer, 2);
> +  if (is_pack_element && token2->type != CPP_LESS)
> + return nullptr;
> +  if (!is_pack_element && token2->type != CPP_OPEN_PAREN)
> + return nullptr;
> +
> +  return 
> +}
>return nullptr;
>  }
>  
> @@ -1215,9 +1227,9 @@ cp_lexer_lookup_trait (const cp_token *token)
> built-in trait.  */
>  
>  static const cp_trait *
> -cp_lexer_lookup_trait_expr (const cp_token *token)
> +cp_lexer_peek_trait_expr (cp_lexer *lexer, const cp_token *token1)
>  {
> -  const cp_trait *trait = cp_lexer_lookup_trait (token);
> +  const cp_trait *trait = cp_lexer_peek_trait (lexer, token1);
>if (trait && !trait->type)
>  return trait;
>  
> @@ -1228,9 +1240,9 @@ cp_lexer_lookup_trait_expr (const cp_token *token)
> built-in trait.  */
>  
>  static const cp_trait *
> -cp_lexer_lookup_trait_type (const cp_token *token)
> +cp_lexer_peek_trait_type (cp_lexer *lexer, const cp_token *token1)
>  {
> -  const cp_trait *trait = cp_lexer_lookup_trait (token);
> +  const cp_trait *trait = cp_lexer_peek_trait (lexer, token1);
>if (trait && trait->type)
>  return trait;
>  
> @@ -1245,7 +1257,7 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer 
> *lexer)
>cp_token *token;
>  
>token = cp_lexer_peek_token (lexer);
> -  if (cp_lexer_lookup_trait_type (token))
> +  if (cp_lexer_peek_trait_type (lexer, token))
>  return true;
>return cp_keyword_starts_decl_specifier_p (token->keyword);
>  }
> @@ -6117,7 +6129,7 @@ cp_parser_primary_expression (cp_parser *parser,
>keyword.  */
>  case CPP_NAME:
>{
> - const cp_trait* trait = cp_lexer_lookup_trait_expr (token);
> + const cp_trait* trait = cp_lexer_peek_trait_expr (parser->lexer, token);
>   if (trait)
> return cp_parser_trait 

Re: [PATCH v20 02/40] c-family, c++: Look up built-in traits via identifier node

2023-10-16 Thread Patrick Palka
On Sun, 15 Oct 2023, Ken Matsui wrote:

> Since RID_MAX soon reaches 255 and all built-in traits are used approximately
> once in a C++ translation unit, this patch removes all RID values for built-in
> traits and uses the identifier node to look up the specific trait.  Rather
> than holding traits as keywords, we set all trait identifiers as cik_trait,
> which is a new cp_identifier_kind.  As cik_reserved_for_udlit was unused and
> cp_identifier_kind is 3 bits, we replaced the unused field with the new
> cik_trait.  Also, the later patch handles a subsequent token to the built-in
> identifier so that we accept the use of non-function-like built-in trait
> identifiers.

Thanks, this looks great!  Some review comments below.

> 
> gcc/c-family/ChangeLog:
> 
>   * c-common.cc (c_common_reswords): Remove all mappings of
>   built-in traits.
>   * c-common.h (enum rid): Remove all RID values for built-in traits.
> 
> gcc/cp/ChangeLog:
> 
>   * cp-objcp-common.cc (names_builtin_p): Remove all RID value
>   cases for built-in traits.  Check for built-in traits via
>   the new cik_trait kind.
>   * cp-tree.h (enum cp_trait_kind): Set its underlying type to
>   addr_space_t.
>   (struct cp_trait): New struct to hold trait information.
>   (cp_traits): New array to hold a mapping to all traits.
>   (cik_reserved_for_udlit): Rename to ...
>   (cik_trait): ... this.
>   (IDENTIFIER_ANY_OP_P): Exclude cik_trait.
>   (IDENTIFIER_TRAIT_P): New macro to detect cik_trait.
>   * lex.cc (init_cp_traits): New function to set cik_trait for all
>   built-in trait identifiers.

We should mention setting IDENTIFIER_CP_INDEX as well.

>   (cxx_init): Call init_cp_traits function.
>   * parser.cc (cp_traits): Define its values, declared in cp-tree.h.
>   (cp_lexer_lookup_trait): New function to look up a
>   built-in trait by IDENTIFIER_CP_INDEX.
>   (cp_lexer_lookup_trait_expr): Likewise, look up an
>   expression-yielding built-in trait.
>   (cp_lexer_lookup_trait_type): Likewise, look up a type-yielding
>   built-in trait.
>   (cp_keyword_starts_decl_specifier_p): Remove all RID value cases
>   for built-in traits.
>   (cp_lexer_next_token_is_decl_specifier_keyword): Handle
>   type-yielding built-in traits.
>   (cp_parser_primary_expression): Remove all RID value cases for
>   built-in traits.  Handle expression-yielding built-in traits.
>   (cp_parser_trait): Handle cp_trait instead of enum rid.
>   (cp_parser_simple_type_specifier): Remove all RID value cases
>   for built-in traits.  Handle type-yielding built-in traits.
> 
> Co-authored-by: Patrick Palka 
> Signed-off-by: Ken Matsui 
> ---
>  gcc/c-family/c-common.cc  |   7 --
>  gcc/c-family/c-common.h   |   5 --
>  gcc/cp/cp-objcp-common.cc |   8 +--
>  gcc/cp/cp-tree.h  |  31 ++---
>  gcc/cp/lex.cc |  21 ++
>  gcc/cp/parser.cc  | 141 --
>  6 files changed, 139 insertions(+), 74 deletions(-)
> 
> diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
> index f044db5b797..21fd333ef57 100644
> --- a/gcc/c-family/c-common.cc
> +++ b/gcc/c-family/c-common.cc
> @@ -508,13 +508,6 @@ const struct c_common_resword c_common_reswords[] =
>{ "wchar_t",   RID_WCHAR,  D_CXXONLY },
>{ "while", RID_WHILE,  0 },
>  
> -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> -  { NAME,RID_##CODE, D_CXXONLY },
> -#include "cp/cp-trait.def"
> -#undef DEFTRAIT
> -  /* An alias for __is_same.  */
> -  { "__is_same_as",  RID_IS_SAME,D_CXXONLY },
> -
>/* C++ transactional memory.  */
>{ "synchronized",  RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
>{ "atomic_noexcept",   RID_ATOMIC_NOEXCEPT, D_CXXONLY | D_TRANSMEM },
> diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> index 1fdba7ef3ea..051a442e0f4 100644
> --- a/gcc/c-family/c-common.h
> +++ b/gcc/c-family/c-common.h
> @@ -168,11 +168,6 @@ enum rid
>RID_BUILTIN_LAUNDER,
>RID_BUILTIN_BIT_CAST,
>  
> -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> -  RID_##CODE,
> -#include "cp/cp-trait.def"
> -#undef DEFTRAIT
> -
>/* C++11 */
>RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
>  
> diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
> index 93b027b80ce..b1adacfec07 100644
> --- a/gcc/cp/cp-objcp-common.cc
> +++ b/gcc/cp/cp-objcp-common.cc
> @@ -421,6 +421,10 @@ names_builtin_p (const char *name)
>   }
>  }
>  
> +  /* Check 

<    1   2   3   4   5   6   7   8   9   10   >