[PATCH] c++: merge tsubst_copy into tsubst_copy_and_build

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

-- >8 --

The relationship between tsubst_copy_and_build and tsubst_copy (two of
the main template argument substitution routines for expression trees)
is rather hazy.  The former is mostly a superset of the latter, with
some differences.

The main difference is that they handle many tree codes differently, but
much of the tree code handling in tsubst_copy appears to be dead code[1].
This is because tsubst_copy only gets directly called in a few places
and mostly on id-expressions.  The interesting exceptions are PARM_DECL,
VAR_DECL, BIT_NOT_EXPR, SCOPE_REF, TEMPLATE_ID_EXPR and IDENTIFIER_NODE:

 * for PARM_DECL and VAR_DECL, tsubst_copy_and_build calls tsubst_copy
   followed by doing some extra handling of its own
 * for BIT_NOT_EXPR tsubst_copy implicitly handles unresolved destructor
   calls (i.e. the first operand is an identifier or a type)
 * for SCOPE_REF, TEMPLATE_ID_EXPR and IDENTIFIER_NODE tsubst_copy
   refrains from doing name lookup of the terminal name

Other more minor differences are that tsubst_copy exits early when
'args' is null, and it calls maybe_dependent_member_ref, and finally
it dispatches to tsubst for type trees.

Thus tsubst_copy is (at this point) similar enough to tsubst_copy_and_build
that it makes sense to merge the two functions, with the main difference
being the name lookup behavior[2].  So this patch merges tsubst_copy into
tsubst_copy_and_build via a new tsubst tf_no_name_lookup which controls
name lookup and resolution of a (top-level) id-expression.

[1]: http://thrifty.mooo.com:8008/gcc-lcov/gcc/cp/pt.cc.gcov.html#17231
[2]: I don't know the history of tsubst_copy but I would guess it was
added before we settled on using processing_template_decl to control
whether our AST building routines perform semantic checking and return
non-templated trees, and so we needed a separate tsubst routine that
avoids semantic checking and always returns a templated tree for e.g.
partial substitution.

gcc/cp/ChangeLog:

* cp-tree.h (enum tsubst_flags): Add tf_no_name_lookup.
* pt.cc (tsubst_copy):
(tsubst_pack_expansion): Use tsubst for substituting BASES_TYPE.
(tsubst_decl) : Use tsubst_copy_and_build with
tf_no_name_lookup instead of tsubst_copy.
(tsubst) : Use tsubst_copy_and_build
instead of tsubst_copy for substituting
CLASS_PLACEHOLDER_TEMPLATE.
: Use tsubst_copy_and_build with
tf_no_name_lookup instead of tsubst_copy for substituting
TYPENAME_TYPE_FULLNAME.
(tsubst_qualified_id): Likewise for substituting the component
name of a SCOPE_REF.
(tsubst_copy): Remove.
(tsubst_copy_and_build): Clear tf_no_name_lookup at the start,
and remember if it was set.  Call maybe_dependent_member_ref.
: Don't do name lookup if tf_no_name_lookup
was set.
: Don't finish a template-id if
tf_no_name_lookup was set.
: Handle identifier and type operand (if
tf_no_name_lookup was set).
: Avoid trying to resolve a SCOPE_REF if
tf_no_name_lookup by calling build_qualified_name directly
instead of tsubst_qualified_id.
: Handling of sizeof...  copied from tsubst_copy.
: Use tsubst_copy_and_build with
tf_no_name_lookup instead of tsubst_copy to substitute
a TEMPLATE_ID_EXPR callee naming an unresolved template.
: Likewise to substitute the member.
: Copied from tsubst_copy and merged with ...
: ... these.  Initial handling copied
from tsubst_copy.  Optimize local variable substitution by
trying retrieve_local_specialization before checking
uses_template_parms.
: Copied from tsubst_copy.
: Likewise.
: Likewise.
: Likewise.
: Likewise.
: Likewise.
: Likewise.
: Likewise.
: Likewise.
: Likewise.
: Likewise.
: Likewise.
: Likewise.
: Likewise.
: Likewise.
: Use tsubst and tsubst_copy_and_build instead
of tsubst_copy.
: Copied from tsubst_copy.
(tsubst_initializer_list): Use tsubst and tsubst_copy_and_build
instead of tsubst_copy.
---
 gcc/cp/cp-tree.h |3 +
 gcc/cp/pt.cc | 1742 +++---
 2 files changed, 719 insertions(+), 1026 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 8b9a7d58462..919eab34803 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5619,6 +5619,9 @@ enum tsubst_flags {
   tf_qualifying_scope = 1 << 14, /* Substituting the LHS of the :: operator.
Affects TYPENAME_TYPE resolution from
make_typename_type.  */
+  tf_no_name_lookup = 1 << 15, /* Don't look up the terminal name of an
+ outermost id-expression, 

Re: [PATCH] c++: merge tsubst_copy into tsubst_copy_and_build

2023-10-03 Thread Patrick Palka
On Mon, 2 Oct 2023, Patrick Palka wrote:

> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> OK for trunk?
> 
> -- >8 --
> 
> The relationship between tsubst_copy_and_build and tsubst_copy (two of
> the main template argument substitution routines for expression trees)
> is rather hazy.  The former is mostly a superset of the latter, with
> some differences.
> 
> The main difference is that they handle many tree codes differently, but
> much of the tree code handling in tsubst_copy appears to be dead code[1].
> This is because tsubst_copy only gets directly called in a few places
> and mostly on id-expressions.  The interesting exceptions are PARM_DECL,
> VAR_DECL, BIT_NOT_EXPR, SCOPE_REF, TEMPLATE_ID_EXPR and IDENTIFIER_NODE:
> 
>  * for PARM_DECL and VAR_DECL, tsubst_copy_and_build calls tsubst_copy
>followed by doing some extra handling of its own
>  * for BIT_NOT_EXPR tsubst_copy implicitly handles unresolved destructor
>calls (i.e. the first operand is an identifier or a type)
>  * for SCOPE_REF, TEMPLATE_ID_EXPR and IDENTIFIER_NODE tsubst_copy
>refrains from doing name lookup of the terminal name
> 
> Other more minor differences are that tsubst_copy exits early when
> 'args' is null, and it calls maybe_dependent_member_ref, and finally
> it dispatches to tsubst for type trees.
> 
> Thus tsubst_copy is (at this point) similar enough to tsubst_copy_and_build
> that it makes sense to merge the two functions, with the main difference
> being the name lookup behavior[2].  So this patch merges tsubst_copy into
> tsubst_copy_and_build via a new tsubst tf_no_name_lookup which controls
> name lookup and resolution of a (top-level) id-expression.
> 
> [1]: http://thrifty.mooo.com:8008/gcc-lcov/gcc/cp/pt.cc.gcov.html#17231
> [2]: I don't know the history of tsubst_copy but I would guess it was
> added before we settled on using processing_template_decl to control
> whether our AST building routines perform semantic checking and return
> non-templated trees, and so we needed a separate tsubst routine that
> avoids semantic checking and always returns a templated tree for e.g.
> partial substitution.

Oops, this is wrong -- tsubst_copy_and_build came after tsubst_copy,
and was introduced as an optimization with the intent of getting rid
of tsubst_copy eventually:
https://gcc.gnu.org/pipermail/gcc-patches/2003-January/093659.html

> 
> gcc/cp/ChangeLog:
> 
>   * cp-tree.h (enum tsubst_flags): Add tf_no_name_lookup.
>   * pt.cc (tsubst_copy):
>   (tsubst_pack_expansion): Use tsubst for substituting BASES_TYPE.
>   (tsubst_decl) : Use tsubst_copy_and_build with
>   tf_no_name_lookup instead of tsubst_copy.
>   (tsubst) : Use tsubst_copy_and_build
>   instead of tsubst_copy for substituting
>   CLASS_PLACEHOLDER_TEMPLATE.
>   : Use tsubst_copy_and_build with
>   tf_no_name_lookup instead of tsubst_copy for substituting
>   TYPENAME_TYPE_FULLNAME.
>   (tsubst_qualified_id): Likewise for substituting the component
>   name of a SCOPE_REF.
>   (tsubst_copy): Remove.
>   (tsubst_copy_and_build): Clear tf_no_name_lookup at the start,
>   and remember if it was set.  Call maybe_dependent_member_ref.
>   : Don't do name lookup if tf_no_name_lookup
>   was set.
>   : Don't finish a template-id if
>   tf_no_name_lookup was set.
>   : Handle identifier and type operand (if
>   tf_no_name_lookup was set).
>   : Avoid trying to resolve a SCOPE_REF if
>   tf_no_name_lookup by calling build_qualified_name directly
>   instead of tsubst_qualified_id.
>   : Handling of sizeof...  copied from tsubst_copy.
>   : Use tsubst_copy_and_build with
>   tf_no_name_lookup instead of tsubst_copy to substitute
>   a TEMPLATE_ID_EXPR callee naming an unresolved template.
>   : Likewise to substitute the member.
>   : Copied from tsubst_copy and merged with ...
>   : ... these.  Initial handling copied
>   from tsubst_copy.  Optimize local variable substitution by
>   trying retrieve_local_specialization before checking
>   uses_template_parms.
>   : Copied from tsubst_copy.
>   : Likewise.
>   : Likewise.
>   : Likewise.
>   : Likewise.
>   : Likewise.
>   : Likewise.
>   : Likewise.
>   : Likewise.
>   : Likewise.
>   : Likewise.
>   : Likewise.
>   : Likewise.
>   : Likewise.
>   : Likewise.
>   : Use tsubst and tsubst_copy_and_build instead
>   of tsubst_copy.
>   : Copied from tsubst_copy.
>   (tsubst_initializer_list): Use tsubst and tsubst_copy_and_build
>   instead of 

Re: [PATCH] c++: merge tsubst_copy into tsubst_copy_and_build

2023-10-04 Thread Patrick Palka
On Tue, 3 Oct 2023, Jason Merrill wrote:

> On 10/3/23 08:41, Patrick Palka wrote:
> > On Mon, 2 Oct 2023, Patrick Palka wrote:
> > 
> > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> > > OK for trunk?
> > > 
> > > -- >8 --
> > > 
> > > The relationship between tsubst_copy_and_build and tsubst_copy (two of
> > > the main template argument substitution routines for expression trees)
> > > is rather hazy.  The former is mostly a superset of the latter, with
> > > some differences.
> > > 
> > > The main difference is that they handle many tree codes differently, but
> > > much of the tree code handling in tsubst_copy appears to be dead code[1].
> > > This is because tsubst_copy only gets directly called in a few places
> > > and mostly on id-expressions.  The interesting exceptions are PARM_DECL,
> > > VAR_DECL, BIT_NOT_EXPR, SCOPE_REF, TEMPLATE_ID_EXPR and IDENTIFIER_NODE:
> > > 
> > >   * for PARM_DECL and VAR_DECL, tsubst_copy_and_build calls tsubst_copy
> > > followed by doing some extra handling of its own
> > >   * for BIT_NOT_EXPR tsubst_copy implicitly handles unresolved destructor
> > > calls (i.e. the first operand is an identifier or a type)
> > >   * for SCOPE_REF, TEMPLATE_ID_EXPR and IDENTIFIER_NODE tsubst_copy
> > > refrains from doing name lookup of the terminal name
> > > 
> > > Other more minor differences are that tsubst_copy exits early when
> > > 'args' is null, and it calls maybe_dependent_member_ref
> 
> That's curious, since what that function does seems like name lookup; I
> wouldn't think we would want to call it when tf_no_name_lookup.

Ah, that makes sense I think.

> 
> > > and finally it dispatches to tsubst for type trees.
> 
> And it looks like you fix the callers to avoid that?

Yes, I'll make a note of that in the commit message.

> 
> > > Thus tsubst_copy is (at this point) similar enough to
> > > tsubst_copy_and_build
> > > that it makes sense to merge the two functions, with the main difference
> > > being the name lookup behavior[2].  So this patch merges tsubst_copy into
> > > tsubst_copy_and_build via a new tsubst tf_no_name_lookup which controls
> > > name lookup and resolution of a (top-level) id-expression.
> > > 
> > > [1]: http://thrifty.mooo.com:8008/gcc-lcov/gcc/cp/pt.cc.gcov.html#17231
> > > [2]: I don't know the history of tsubst_copy but I would guess it was
> > > added before we settled on using processing_template_decl to control
> > > whether our AST building routines perform semantic checking and return
> > > non-templated trees, and so we needed a separate tsubst routine that
> > > avoids semantic checking and always returns a templated tree for e.g.
> > > partial substitution.
> > 
> > Oops, this is wrong -- tsubst_copy_and_build came after tsubst_copy,
> > and was introduced as an optimization with the intent of getting rid
> > of tsubst_copy eventually:
> > https://gcc.gnu.org/pipermail/gcc-patches/2003-January/093659.html
> 
> I wonder if we want to add a small tsubst_name wrapper to call
> tsubst_copy_and_build with tf_no_name_lookup?

Good idea, that'll complement tsubst_scope nicely.

> 
> Can we also merge in tsubst_expr and use that name instead of the unwieldy
> tsubst_copy_and_build?

That'd be nice.  Another idea would be to rename tsubst_expr to
tsubst_stmt and make it disjoint from tsubst_copy_and_build, and then
rename tsubst_copy_and_build to tsubst_expr, to draw a distinction
between statement-like trees (the substitution of which typically has
side effects like calling add_stmt) and expression-like trees (which
don't usually have such side effects).  I can work on that as a
follow-up patch.

Here's v2 which guards the call to maybe_dependent_member_ref and adds
tsubst_name, bootstrapped and regtested on x86_64-pc-linux-gnu:

-- >8 --

Subject: [PATCH] c++: merge tsubst_copy into tsubst_copy_and_build

gcc/cp/ChangeLog:

* cp-tree.h (enum tsubst_flags): Add tf_no_name_lookup.
* pt.cc (tsubst_copy):
(tsubst_pack_expansion): Use tsubst for substituting BASES_TYPE.
(tsubst_decl) : Use tsubst_name instead of
tsubst_copy.
(tsubst) : Use tsubst_copy_and_build
instead of tsubst_copy for substituting
CLASS_PLACEHOLDER_TEMPLATE.
: Use tsubst_name instead of tsubst_copy for
substituting TYPENAME_TYPE_FULLNAME.
(tsubst_name): Define.
(tsubst_qualified_id): Use tsubst_name instead of tsubst_copy
for substituting the compon

[PATCH 2/1] c++: rename tsubst_copy_and_build and tsubst_expr

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

-- >8 --

After the previous patch, we currently have two tsubst entry points
for expression trees: tsubst_copy_and_build and tsubst_expr.  But the
latter is just a superset of the former that also handles statement
trees.  We could merge the two entry points so that we just have
tsubst_expr, but it seems natural to distinguish statement trees from
expression trees and to maintain a separate entry point for them.

To that end, this this patch renames tsubst_copy_and_build to
tsubst_expr, and renames the current tsubst_expr to tsubst_stmt, which
continues to be a superset of the former (since sometimes expression
trees appear in statement contexts, e.g. a branch of an IF_STMT could be
NOP_EXPR).  Making tsubst_stmt disjoint from tsubst_expr is left as
future work (if deemed desirable).

This patch in turn renames suitable existing uses of tsubst_expr (that
expect to take statement trees) to use tsubst_stmt.  Thus untouched
tsubst_expr calls are implicitly strengthened to expect only expression
trees after this patch.  And since I'm not familiar with the
tsubst_omp_* routines this patch renames all tsubst_expr uses there to
tsubst_stmt to ensure no unintended functional change in that area.
This patch also moves the handling of CO_YIELD_EXPR and CO_AWAIT_EXPR
from tsubst_stmt to tsubst_expr since they're expression trees.

gcc/cp/ChangeLog:

* cp-lang.cc (objcp_tsubst_copy_and_build): Rename to ...
(objcp_tsubst_expr): ... this.
* cp-objcp-common.h (objcp_tsubst_copy_and_build): Rename to ...
(objcp_tsubst_expr): ... this.
* cp-tree.h (tsubst_copy_and_build): Remove declaration.
* init.cc (maybe_instantiate_nsdmi_init): Use tsubst_expr
instead of tsubst_copy_and_build.
* pt.cc (expand_integer_pack): Likewise.
(instantiate_non_dependent_expr_internal): Likewise.
(instantiate_class_template): Use tsubst_stmt instead of
tsubst_expr for STATIC_ASSERT.
(tsubst_function_decl): Adjust tsubst_copy_and_build uses.
(tsubst_arg_types): Likewise.
(tsubst_exception_specification): Likewise.
(tsubst_tree_list): Likewise.
(tsubst): Likewise.
(tsubst_name): Likewise.
(tsubst_omp_clause_decl): Use tsubst_stmt instead of tsubst_expr.
(tsubst_omp_clauses): Likewise.
(tsubst_copy_asm_operands): Adjust tsubst_copy_and_build use.
(tsubst_omp_for_iterator): Use tsubst_stmt instead of tsubst_expr.
(tsubst_expr): Rename to ...
(tsubst_stmt): ... this.
: Move to tsubst_expr.
(tsubst_omp_udr): Use tsubst_stmt instead of tsubst_expr.
(tsubst_non_call_postfix_expression): Adjust tsubst_copy_and_build
use.
(tsubst_lambda_expr): Likewise.  Use tsubst_stmt instead of
tsubst_expr for the body of a lambda.
(tsubst_copy_and_build_call_args): Rename to ...
(tsubst_call_args): ... this.  Adjust tsubst_copy_and_build use.
(tsubst_copy_and_build): Rename to tsubst_expr.  Adjust
tsubst_copy_and_build and tsubst_copy_and_build_call_args use.
: Use tsubst_stmt instead of tsubst_expr.
(maybe_instantiate_noexcept): Adjust tsubst_copy_and_build use.
(instantiate_body): Use tsubst_stmt instead of tsubst_expr for
substituting the function body.
(tsubst_initializer_list): Adjust tsubst_copy_and_build use.

gcc/objcp/ChangeLog:

* objcp-lang.cc (objcp_tsubst_copy_and_build): Rename to ...
(objcp_tsubst_expr): ... this.  Adjust tsubst_copy_and_build
uses.
---
 gcc/cp/cp-lang.cc|   6 +-
 gcc/cp/cp-objcp-common.h |   2 +-
 gcc/cp/cp-tree.h |   1 -
 gcc/cp/init.cc   |   3 +-
 gcc/cp/pt.cc | 177 +--
 gcc/objcp/objcp-lang.cc  |   5 +-
 6 files changed, 85 insertions(+), 109 deletions(-)

diff --git a/gcc/cp/cp-lang.cc b/gcc/cp/cp-lang.cc
index 2f541460c4a..f2ed83de4fb 100644
--- a/gcc/cp/cp-lang.cc
+++ b/gcc/cp/cp-lang.cc
@@ -113,10 +113,8 @@ struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
 /* The following function does something real, but only in Objective-C++.  */
 
 tree
-objcp_tsubst_copy_and_build (tree /*t*/,
-tree /*args*/,
-tsubst_flags_t /*complain*/,
-tree /*in_decl*/)
+objcp_tsubst_expr (tree /*t*/, tree /*args*/, tsubst_flags_t /*complain*/,
+  tree /*in_decl*/)
 {
   return NULL_TREE;
 }
diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h
index 80893aa1752..1408301a300 100644
--- a/gcc/cp/cp-objcp-common.h
+++ b/gcc/cp/cp-objcp-common.h
@@ -24,7 +24,7 @@ along with GCC; see the file COPYING3.  If not see
 /* In cp/objcp-common.c, cp/cp-lang.cc and objcp/objcp-lang.cc.  */
 
 extern tree cp_get_debug_type (const_tree);
-extern tree objcp_tsubst_copy_and_build 

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

2023-10-09 Thread Patrick Palka
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 | 161 +++--
 gcc/testsuite/g++.dg/overload/error5.C |  11 ++
 2 files changed, 111 insertions(+), 61 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/overload/error5.C

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 15079ddf6dc..648d383ca4e 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 *);
@@ -3718,68 +3720,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 = &strictly_viable;
+
+  z_candidate *non_strictly_viable = nullptr;
+  z_candidate **non_strictly_viable_tail = &non_strictly_viable;
+
+  z_candidate *unviable = nullptr;
+  z_candidate **unviable_tail = &unviable;
 
   /* 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 = &viable;
-  *any_viable_p = false;
-
-  cand = &cands;
-  while (*cand)
+  for (z_candidate *cand = cands; cand; cand = cand->next)
 {
-  struct z_candidate *c = *cand;
   

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

2023-10-09 Thread Patrick Palka
With the previous improvements in place, we can easily extend our
deletedness diagnostic to note the other candidates:

  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 disabled when a deleted special member function is
selected primarily 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 at
A(A&&).

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 | 11 +++
 2 files changed, 20 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 648d383ca4e..55fd71636b1 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -9873,7 +9873,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..9fd2fbb1465
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/deleted16.C
@@ -0,0 +1,11 @@
+// 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" }
+
+int main() {
+  f(0); // { dg-error "deleted" }
+}
-- 
2.42.0.325.g3a06386e31



Re: [PATCH v16 02/39] c-family, c++: Look up built-in traits through gperf

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

> Since RID_MAX soon reaches 255 and all traits are used approximately once in
> a C++ translation unit, this patch instead uses only RID_TRAIT_EXPR and
> RID_TRAIT_TYPE for all traits and uses gperf to look up the specific trait.

Nice!  This looks good to me, but I wonder what the corresponding
ridpointers entry should be for RID_TRAIT_TYPE and RID_TRAIT_EXPR?  It
seems we currently assume every rid code has a unique canonical spelling
which we keep in ridpointers[RID_FOO], but that's of course not the case
for RID_TRAIT_TYPE and RID_TRAIT_EXPR.  Maybe we should make
init_reswords() keep the ridpointers entry empty for RID_TRAIT_EXPR and
RID_TRAIT_TYPE?

> 
> gcc/c-family/ChangeLog:
> 
>   * c-common.cc (c_common_reswords): Map all traits to RID_TRAIT_EXPR
>   and RID_TRAIT_TYPE instead.
>   * c-common.h (enum rid): Remove all existing RID values for traits.
>   Use RID_TRAIT_EXPR and RID_TRAIT_TYPE instead.
> 
> gcc/cp/ChangeLog:
> 
>   * Make-lang.in: Add targets to generate cp-trait.gperf and
>   cp-trait.h.
>   * cp-objcp-common.cc (names_builtin_p): Remove all existing RID values
>   for traits.  Use RID_TRAIT_EXPR and RID_TRAIT_TYPE instead.
>   * parser.cc (cp_keyword_starts_decl_specifier_p): Likewise, for
>   type-yielding traits.  Use RID_TRAIT_TYPE instead.
>   (cp_parser_simple_type_specifier): Likewise.
>   (cp_parser_primary_expression): Likewise, for expression-yielding
>   traits.  Use RID_TRAIT_EXPR instead.
>   (cp_parser_trait): Look up traits through gperf instead of enum rid.
>   * cp-trait-head.in: New file.
>   * cp-trait.gperf: New file.
>   * cp-trait.h: New file.
> 
> Signed-off-by: Ken Matsui 
> ---
>  gcc/c-family/c-common.cc  |  12 +-
>  gcc/c-family/c-common.h   |   7 +-
>  gcc/cp/Make-lang.in   |  24 
>  gcc/cp/cp-objcp-common.cc |   6 +-
>  gcc/cp/cp-trait-head.in   |  30 +
>  gcc/cp/cp-trait.gperf |  74 
>  gcc/cp/cp-trait.h | 247 ++
>  gcc/cp/parser.cc  |  70 ---
>  8 files changed, 412 insertions(+), 58 deletions(-)
>  create mode 100644 gcc/cp/cp-trait-head.in
>  create mode 100644 gcc/cp/cp-trait.gperf
>  create mode 100644 gcc/cp/cp-trait.h
> 
> diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
> index f044db5b797..f219ccd29e5 100644
> --- a/gcc/c-family/c-common.cc
> +++ b/gcc/c-family/c-common.cc
> @@ -508,12 +508,16 @@ 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 },
> +#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
> +  { NAME,RID_TRAIT_EXPR, D_CXXONLY },
>  #include "cp/cp-trait.def"
> -#undef DEFTRAIT
> +#undef DEFTRAIT_EXPR
>/* An alias for __is_same.  */
> -  { "__is_same_as",  RID_IS_SAME,D_CXXONLY },
> +  { "__is_same_as",  RID_TRAIT_EXPR, D_CXXONLY },
> +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> +  { NAME,RID_TRAIT_TYPE, D_CXXONLY },
> +#include "cp/cp-trait.def"
> +#undef DEFTRAIT_TYPE
>  
>/* C++ transactional memory.  */
>{ "synchronized",  RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
> diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> index 1fdba7ef3ea..a1a641f4175 100644
> --- a/gcc/c-family/c-common.h
> +++ b/gcc/c-family/c-common.h
> @@ -168,10 +168,9 @@ 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++ traits, defined in cp-trait.def.  */
> +  RID_TRAIT_EXPR,
> +  RID_TRAIT_TYPE,
>  
>/* C++11 */
>RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
> diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
> index 2727fb7f8cc..8d4e3a1f594 100644
> --- a/gcc/cp/Make-lang.in
> +++ b/gcc/cp/Make-lang.in
> @@ -34,6 +34,8 @@
>  # - the compiler proper (eg: cc1plus)
>  # - define the names for selecting the language in LANGUAGES.
>  
> +AWK = @AWK@
> +
>  # Actual names to use when installing a native compiler.
>  CXX_INSTALL_NAME := $(shell echo c++|sed '$(program_transform_name)')
>  GXX_INSTALL_NAME := $(shell echo g++|sed '$(program_transform_name)')
> @@ -186,6 +188,28 @@ endif
>  # This is the file that depends on the generated header file.
>  cp/name-lookup.o: $(srcdir)/cp/std-name-hint.h
>  
> +# We always need the dependency on the .gperf file because it itself is 
> generated.
> +ifeq ($(ENABLE_MAINTAINER_RULES), true)
> +$(srcdir)/cp/cp-trait.h: $(srcdir)/cp/cp-trait.gperf
> +else
> +$(srcdir)/cp/cp-trait.h: | $(srcdir)/cp/cp-trait.gperf
> +endif
> + gperf -o -C -E -k '8' -D -N 'find' -L C++ \
> + $(srcdir)/cp/cp-trait.gperf --output-file 
> $(srcdir)/cp/cp-trait.h
> +
> +# The cp-trait.gperf f

Re: [PATCH v17 02/39] c-family, c++: Look up built-in traits through gperf

2023-10-12 Thread Patrick Palka
On Wed, 11 Oct 2023, Ken Matsui wrote:

> Since RID_MAX soon reaches 255 and all traits are used approximately once in
> a C++ translation unit, this patch instead uses only RID_TRAIT_EXPR and
> RID_TRAIT_TYPE for all traits and uses gperf to look up the specific trait.
> 
> gcc/c-family/ChangeLog:
> 
>   * c-common.cc (c_common_reswords): Map all traits to RID_TRAIT_EXPR
>   and RID_TRAIT_TYPE instead.
>   * c-common.h (enum rid): Remove all existing RID values for traits.
>   Use RID_TRAIT_EXPR and RID_TRAIT_TYPE instead.
> 
> gcc/cp/ChangeLog:
> 
>   * Make-lang.in: Add targets to generate cp-trait.gperf and
>   cp-trait.h.
>   * cp-objcp-common.cc (names_builtin_p): Remove all existing RID values
>   for traits.  Use RID_TRAIT_EXPR and RID_TRAIT_TYPE instead.
>   * parser.cc (cp_keyword_starts_decl_specifier_p): Likewise, for
>   type-yielding traits.  Use RID_TRAIT_TYPE instead.
>   (cp_parser_simple_type_specifier): Likewise.
>   (cp_parser_primary_expression): Likewise, for expression-yielding
>   traits.  Use RID_TRAIT_EXPR instead.
>   (cp_parser_trait): Look up traits through gperf instead of enum rid.
>   * lex.cc (init_reswords): Make ridpointers for RID_TRAIT_EXPR and
>   RID_TRAIT_TYPE empty, which do not have corresponding unique
>   cannonical spellings.
>   * cp-trait-head.in: New file.
>   * cp-trait.gperf: New file.
>   * cp-trait.h: New file.
> 
> Signed-off-by: Ken Matsui 
> ---
>  gcc/c-family/c-common.cc  |  12 +-
>  gcc/c-family/c-common.h   |   7 +-
>  gcc/cp/Make-lang.in   |  26 
>  gcc/cp/cp-objcp-common.cc |   6 +-
>  gcc/cp/cp-trait-head.in   |  30 +
>  gcc/cp/cp-trait.gperf |  74 
>  gcc/cp/cp-trait.h | 247 ++
>  gcc/cp/lex.cc |   5 +
>  gcc/cp/parser.cc  |  70 ---
>  9 files changed, 419 insertions(+), 58 deletions(-)
>  create mode 100644 gcc/cp/cp-trait-head.in
>  create mode 100644 gcc/cp/cp-trait.gperf
>  create mode 100644 gcc/cp/cp-trait.h
> 
> diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
> index f044db5b797..f219ccd29e5 100644
> --- a/gcc/c-family/c-common.cc
> +++ b/gcc/c-family/c-common.cc
> @@ -508,12 +508,16 @@ 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 },
> +#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
> +  { NAME,RID_TRAIT_EXPR, D_CXXONLY },
>  #include "cp/cp-trait.def"
> -#undef DEFTRAIT
> +#undef DEFTRAIT_EXPR
>/* An alias for __is_same.  */
> -  { "__is_same_as",  RID_IS_SAME,D_CXXONLY },
> +  { "__is_same_as",  RID_TRAIT_EXPR, D_CXXONLY },
> +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> +  { NAME,RID_TRAIT_TYPE, D_CXXONLY },
> +#include "cp/cp-trait.def"
> +#undef DEFTRAIT_TYPE
>  
>/* C++ transactional memory.  */
>{ "synchronized",  RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
> diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> index 1fdba7ef3ea..a1a641f4175 100644
> --- a/gcc/c-family/c-common.h
> +++ b/gcc/c-family/c-common.h
> @@ -168,10 +168,9 @@ 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++ traits, defined in cp-trait.def.  */
> +  RID_TRAIT_EXPR,
> +  RID_TRAIT_TYPE,
>  
>/* C++11 */
>RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
> diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
> index 2727fb7f8cc..a67d1c3e9f3 100644
> --- a/gcc/cp/Make-lang.in
> +++ b/gcc/cp/Make-lang.in
> @@ -34,6 +34,8 @@
>  # - the compiler proper (eg: cc1plus)
>  # - define the names for selecting the language in LANGUAGES.
>  
> +AWK = @AWK@
> +
>  # Actual names to use when installing a native compiler.
>  CXX_INSTALL_NAME := $(shell echo c++|sed '$(program_transform_name)')
>  GXX_INSTALL_NAME := $(shell echo g++|sed '$(program_transform_name)')
> @@ -186,6 +188,30 @@ endif
>  # This is the file that depends on the generated header file.
>  cp/name-lookup.o: $(srcdir)/cp/std-name-hint.h
>  
> +# We always need the dependency on the .gperf file
> +# because it itself is generated.
> +ifeq ($(ENABLE_MAINTAINER_RULES), true)
> +$(srcdir)/cp/cp-trait.h: $(srcdir)/cp/cp-trait.gperf
> +else
> +$(srcdir)/cp/cp-trait.h: | $(srcdir)/cp/cp-trait.gperf
> +endif
> + gperf -o -C -E -k '8' -D -N 'find' -L C++ \
> + $(srcdir)/cp/cp-trait.gperf --output-file 
> $(srcdir)/cp/cp-trait.h
> +
> +# The cp-trait.gperf file itself is generated from
> +# cp-trait-head.in and cp-trait.def files.
> +$(srcdir)/cp/cp-trait.gperf: $(srcdir)/cp/cp-trait-head.in 
> $(srcdir)/cp/cp-trait.def
> + cat $< > $@
> + $(AWK) -F', *' '/^DEFTRAIT_/

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

2023-10-12 Thread Patrick Palka
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:

-- >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, args);
- }
-   else if (BASELINK_P (fn))
- {
- postfix_expression
-   = (build_new_method_call
-  (instance, fn, &args, NULL_TREE,
-   (idk == CP_ID_KIND_QUALIFIED
-? LOOKUP_NORMAL|LOOKUP_NONVIRTUAL
-: LOOKUP_NORMAL),
-   /*fn_p=*/NULL,
-   complain));
- }
-   else
- postfix_expression
-   = finish_call_expr (postfix_expression, &args,
-   /*disallow_virtual=*/false,
-   /*koenig_p=*/false,
-   complain);
- }
-   else if (TREE_CODE (postfix_expression) == OFFSET_REF
-|| TREE_CODE (postfix_expression) == MEMBER_REF
-|| TREE_CODE (postfix_expression) == DOTSTAR_EXPR)
+   if (TREE_CODE (postfix_expression) == OFFSET_REF
+   || TREE_CODE (postfix_expression) == MEMBER_REF
+   || TREE_CODE (postfix_expression) == DOTSTAR_EXPR)
  postfix_expression = (build_offset_ref_call_from_tree
(postfix_expression, &args,
 complain))

Re: [PATCH v19 02/40] c-family, c++: Look up built-in traits through gperf

2023-10-15 Thread Patrick Palka
On Fri, 13 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 gperf 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.

Awesome!  It's great we won't have to rename any existing identifiers in
libstdc++ with this approach.

I think this patch looks perfect, assuming we want to stick with the gperf
approach, but I just noticed that IDENTIFIER nodes have an IDENTIFIER_CP_INDEX
field which is currently only used for operator name identifiers to
optimize looking up operator information.  Could we reuse this field for
IDENTIFIER_TRAIT_P identifiers as well in order to store their
corresponding cp_trait_kind?  If so then I think we wouldn't need to use
gperf for the built-in traits at all, since the mapping from identifier
to cp_trait_kind would be implicit in each IDENTIFIER node, which would
perhaps be a nice simplification (and just as fast if not faster than gperf)?

> 
> 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:
> 
>   * Make-lang.in: Add targets to generate cp-trait.gperf and
>   cp-trait.h.
>   * 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 identifier.
>   * cp-tree.h (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.
>   (cxx_init): Call init_cp_traits function.
>   * parser.cc (cp_lexer_lookup_trait): New function to look up a
>   built-in trait from a token by gperf.
>   (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.
>   * cp-trait-head.in: New file.
>   * cp-trait.gperf: New file.
>   * cp-trait.h: New file.
> 
> 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/Make-lang.in   |  26 
>  gcc/cp/cp-objcp-common.cc |   8 +-
>  gcc/cp/cp-trait-head.in   |  30 +
>  gcc/cp/cp-trait.gperf |  74 
>  gcc/cp/cp-trait.h | 247 ++
>  gcc/cp/cp-tree.h  |  14 ++-
>  gcc/cp/lex.cc |  19 +++
>  gcc/cp/parser.cc  | 132 
>  10 files changed, 492 insertions(+), 70 deletions(-)
>  create mode 100644 gcc/cp/cp-trait-head.in
>  create mode 100644 gcc/cp/cp-trait.gperf
>  create mode 100644 gcc/cp/cp-trait.h
> 
> 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 },
>{ &quo

Re: [PATCH v19 02/40] c-family, c++: Look up built-in traits through gperf

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

> On Sun, Oct 15, 2023 at 1:43 PM Patrick Palka  wrote:
> >
> > On Fri, 13 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 gperf 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.
> >
> > Awesome!  It's great we won't have to rename any existing identifiers in
> > libstdc++ with this approach.
> >
> > I think this patch looks perfect, assuming we want to stick with the gperf
> > approach, but I just noticed that IDENTIFIER nodes have an 
> > IDENTIFIER_CP_INDEX
> > field which is currently only used for operator name identifiers to
> > optimize looking up operator information.  Could we reuse this field for
> > IDENTIFIER_TRAIT_P identifiers as well in order to store their
> > corresponding cp_trait_kind?  If so then I think we wouldn't need to use
> > gperf for the built-in traits at all, since the mapping from identifier
> > to cp_trait_kind would be implicit in each IDENTIFIER node, which would
> > perhaps be a nice simplification (and just as fast if not faster than 
> > gperf)?
> >
> 
> Thank you! I think this way decreases the size of the compiler even if
> we do not see speed improvements. Since IDENTIFIER_CP_INDEX
> (base.u.bits.address_space) is an unsigned char (addr_space_t), we can
> have only up to 255 traits. Is this acceptable?

Good points.  Given there's so far around 150 standard library traits, a
limit of 255 should last us quite a while so IMHO it's acceptable :)

> 
> > >
> > > 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:
> > >
> > >   * Make-lang.in: Add targets to generate cp-trait.gperf and
> > >   cp-trait.h.
> > >   * 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 identifier.
> > >   * cp-tree.h (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.
> > >   (cxx_init): Call init_cp_traits function.
> > >   * parser.cc (cp_lexer_lookup_trait): New function to look up a
> > >   built-in trait from a token by gperf.
> > >   (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.
> > >   * cp-trait-head.in: New file.
> > >   * cp-trait.gperf: New file.
> > >   * cp-trait.h: New file.
> > >
> > > 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/Make-lang.in   |  26 
> > >  gcc/cp/cp-objcp-common.cc |   8 +-
> &g

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 

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 &cp_traits[IDENTIFIER_CP_INDEX (id)];
> +{
> +  const cp_trait &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 &trait;
> +}
>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 c

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:
>if

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 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);
> +SA_TEST_CA

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

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

[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 = &b->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 = &TREE_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] 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 = &b->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 = &TREE_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;
> +
> +struc

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 (&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 (&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 bett

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_

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 +++-
>  gcc/testsuite/g++.dg

[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 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
> @

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 = &b->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 = &TREE_CHAIN (*prev);
> > +
> > +  TREE_CHAIN (decl) = *prev;
> > +  *prev = decl;
> >   /* If appropriate, add decl to separate list of statics.  We include
> >

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;
>  }
>  
> +/* Retur

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

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

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

[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



[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 = &strictly_viable;
+
+  z_candidate *non_strictly_viable = nullptr;
+  z_candidate **non_strictly_viable_tail = &non_strictly_viable;
+
+  z_candidate *unviable = nullptr;
+  z_candidate **unviable_tail = &unviable;
 
   /* 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 = &viab

[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 (&reason_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 = &unviable;
 
+  z_candidate *unviable_ignored = nullptr;
+  z_candidate **unviable_ignored_tail = &unviable_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 = &cand->next;
@@ -3751,7 +3784,8 @@ splice_viable (struct z_candida

[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] 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



[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



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];
> > +}
> 
> 

[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



[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++: 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
--- a/gcc/testsuite/g++.dg/warn/Wparenthe

[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



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



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_warn

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;
> +

[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



[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 "dele

[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 (&reason_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 = &non_viable;
 
+  z_candidate *non_viable_ignored = nullptr;
+  z_candidate **non_viable_ignored_tail = &non_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 = &cand->next;
@@ -3751,7 +3785,8 @@ splice_v

[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 **cand

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



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, 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: [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-c

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

[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] 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)
> &&am

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/c

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; };
> -- 
> 
> 
> 

[PATCH] Fix a couple of memory leaks in the C++ frontend

2020-01-20 Thread Patrick Palka
The leak in get_mapped_args is due to auto_vec not properly supporting
destructible elements, in that auto_vec's destructor doesn't call the
destructors of its elements.

Successfully bootstrapped and regtested on x86_64-pc-linux-gnu, OK to commit?

gcc/cp/ChangeLog:

* constraint.cc (get_mapped_args): Avoid using auto_vec
as a vector element.  Release the vectors inside the lists
vector.
* parser.c (cp_literal_operator_id): Free the buffer.
---
 gcc/cp/constraint.cc | 7 ---
 gcc/cp/parser.c  | 1 +
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 128ab8ae0b2..823604afb89 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -2431,7 +2431,7 @@ get_mapped_args (tree map)
  list. Note that the list will be sparse (not all arguments supplied),
  but instantiation is guaranteed to only use the parameters in the
  mapping, so null arguments would never be used.  */
-  auto_vec< auto_vec > lists (count);
+  auto_vec< vec > lists (count);
   lists.quick_grow_cleared (count);
   for (tree p = map; p; p = TREE_CHAIN (p))
 {
@@ -2440,7 +2440,7 @@ get_mapped_args (tree map)
   template_parm_level_and_index (TREE_VALUE (p), &level, &index);
 
   /* Insert the argument into its corresponding position.  */
-  auto_vec &list = lists[level - 1];
+  vec &list = lists[level - 1];
   if (index >= (int)list.length ())
list.safe_grow_cleared (index + 1);
   list[index] = TREE_PURPOSE (p);
@@ -2450,11 +2450,12 @@ get_mapped_args (tree map)
   tree args = make_tree_vec (lists.length ());
   for (unsigned i = 0; i != lists.length (); ++i)
 {
-  auto_vec &list = lists[i];
+  vec &list = lists[i];
   tree level = make_tree_vec (list.length ());
   for (unsigned j = 0; j < list.length(); ++j)
TREE_VEC_ELT (level, j) = list[j];
   SET_TMPL_ARGS_LEVEL (args, i + 1, level);
+  list.release ();
 }
   SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (args, 0);
 
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index c5f9798a5ed..e1e27a574f1 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -15344,6 +15344,7 @@ cp_literal_operator_id (const char* name)
  + strlen (name) + 10);
   sprintf (buffer, UDLIT_OP_ANSI_FORMAT, name);
   identifier = get_identifier (buffer);
+  free (buffer);
 
   return identifier;
 }
-- 
2.25.0.rc0



[PATCH] libstdc++: Always return a sentinel from __gnu_test::test_range::end()

2020-01-21 Thread Patrick Palka
It seems that in practice std::sentinel_for is always true, and so the
test_range container doesn't help us detect bugs in ranges code in which we
wrongly assume that a sentinel can be manipulated like an iterator.  Make the
test_range container more strict by having end() unconditionally return a
sentinel.

Is this OK to commit after bootstrap+regtesting succeeds on x86_64-pc-linux-gnu?

libstdc++-v3/ChangeLog:

* testsuite/util/testsuite_iterators.h (__gnu_test::test_range::end):
Always return a sentinel.
---
 libstdc++-v3/testsuite/util/testsuite_iterators.h | 5 +
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/libstdc++-v3/testsuite/util/testsuite_iterators.h 
b/libstdc++-v3/testsuite/util/testsuite_iterators.h
index eb15257bf6a..6667a3af93a 100644
--- a/libstdc++-v3/testsuite/util/testsuite_iterators.h
+++ b/libstdc++-v3/testsuite/util/testsuite_iterators.h
@@ -702,10 +702,7 @@ namespace __gnu_test
   auto end() &
   {
using I = decltype(get_iterator(bounds.last));
-   if constexpr (std::sentinel_for)
- return get_iterator(bounds.last);
-   else
- return sentinel{bounds.last};
+   return sentinel{bounds.last};
   }
 
   typename Iter::ContainerType bounds;
-- 
2.25.0.rc0



Re: [PATCH] Fix a couple of memory leaks in the C++ frontend

2020-01-22 Thread Patrick Palka

On Tue, 21 Jan 2020, Jason Merrill wrote:


On 1/20/20 8:06 PM, Patrick Palka wrote:

The leak in get_mapped_args is due to auto_vec not properly supporting
destructible elements, in that auto_vec's destructor doesn't call the
destructors of its elements.


Hmm, perhaps vec should static_assert __is_trivial(T) when supported.


Unfortunately this would break other seemingly well-behaved users of vec
in which T doesn't have a trivial default constructor.  Relaxing the
condition to __has_trivial_copy(T) && __has_trivial_destructor(T) seems
to be fine though.




@@ -15344,6 +15344,7 @@ cp_literal_operator_id (const char* name)
  + strlen (name) + 10);
sprintf (buffer, UDLIT_OP_ANSI_FORMAT, name);
identifier = get_identifier (buffer);
+  free (buffer);


I guess we should use XDELETEVEC to match XNEWVEC.  OK with that change.


Patch committed with that change.



Jason






Re: [PATCH] libstdc++: Always return a sentinel from __gnu_test::test_range::end()

2020-01-29 Thread Patrick Palka

On Wed, 29 Jan 2020, Jonathan Wakely wrote:


On 21/01/20 17:26 -0500, Patrick Palka wrote:
It seems that in practice std::sentinel_for is always true, and so 
the


Doh, good catch.


test_range container doesn't help us detect bugs in ranges code in which we
wrongly assume that a sentinel can be manipulated like an iterator.  Make 
the

test_range container more strict by having end() unconditionally return a
sentinel.


Yes, this seems useful.

Is this OK to commit after bootstrap+regtesting succeeds on 
x86_64-pc-linux-gnu?


As you mentioned on IRC, this makes some tests fail.

Some of them are bad tests and this change reveals that, e.g.
std/ranges/access/end.cc should not assume that r.end()==r.end() is
valid (because sentinels can't be compared with sentinels).

In other cases, the test is intentionally relying on the fact the
r.end() returns the same type as r.begin(), e.g. in 
std/ranges/access/rbegin.cc we want to test this case:


— Otherwise, make_reverse_iterator(ranges::end(t)) if both
 ranges::begin(t) and ranges::end(t) are valid expressions of the same
 type I which models bidirectional_iterator (23.3.4.12).

If the sentinel returned by ranges::end(r) is a different type, we
can't use test_range to verify this part of the ranges::rbegin
requirements.

I think we do want your change, so this patch fixes the tests that
inappropriately assume the sentinel is the same type as the iterator.
When we are actually relying on that property for the test, I'm adding
a new type derived from test_range which provides that guarantee and
using that instead.

There's one final change needed to make std/ranges/access/size.cc
compile after your patch, which is to make the test_range::sentinel
type satisfy std::sized_sentinel_for when the iterator satisfies
std::random_access_iterator, i.e. support subtracting iterators and
sentinels from each other.

Tested powerpc64le-linux, committed to trunk.


Thanks for the review and the testsuite fixes.



Please go ahead and commit your patch to test_range::end() after
re-testing. Thanks, and congratulations on your first libstdc++
patch.


Thanks! :)  I am re-testing now, and will commit the patch after that's
done.






Re: [PATCH] libstdc++: Always return a sentinel from __gnu_test::test_range::end()

2020-01-29 Thread Patrick Palka

On Wed, 29 Jan 2020, Patrick Palka wrote:


On Wed, 29 Jan 2020, Jonathan Wakely wrote:


On 21/01/20 17:26 -0500, Patrick Palka wrote:
It seems that in practice std::sentinel_for is always true, and so 
the


Doh, good catch.

test_range container doesn't help us detect bugs in ranges code in which 
we
wrongly assume that a sentinel can be manipulated like an iterator.  Make 
the

test_range container more strict by having end() unconditionally return a
sentinel.


Yes, this seems useful.

Is this OK to commit after bootstrap+regtesting succeeds on 
x86_64-pc-linux-gnu?


As you mentioned on IRC, this makes some tests fail.

Some of them are bad tests and this change reveals that, e.g.
std/ranges/access/end.cc should not assume that r.end()==r.end() is
valid (because sentinels can't be compared with sentinels).

In other cases, the test is intentionally relying on the fact the
r.end() returns the same type as r.begin(), e.g. in 
std/ranges/access/rbegin.cc we want to test this case:


— Otherwise, make_reverse_iterator(ranges::end(t)) if both
 ranges::begin(t) and ranges::end(t) are valid expressions of the same
 type I which models bidirectional_iterator (23.3.4.12).

If the sentinel returned by ranges::end(r) is a different type, we
can't use test_range to verify this part of the ranges::rbegin
requirements.

I think we do want your change, so this patch fixes the tests that
inappropriately assume the sentinel is the same type as the iterator.
When we are actually relying on that property for the test, I'm adding
a new type derived from test_range which provides that guarantee and
using that instead.

There's one final change needed to make std/ranges/access/size.cc
compile after your patch, which is to make the test_range::sentinel
type satisfy std::sized_sentinel_for when the iterator satisfies
std::random_access_iterator, i.e. support subtracting iterators and
sentinels from each other.

Tested powerpc64le-linux, committed to trunk.


Thanks for the review and the testsuite fixes.



Please go ahead and commit your patch to test_range::end() after
re-testing. Thanks, and congratulations on your first libstdc++
patch.


Thanks! :)  I am re-testing now, and will commit the patch after that's
done.


It looks like there are other testsuite failures that need to get
addressed, in particular in the tests
range_operations/{prev,distance,next}.cc.

In prev.cc and next.cc we are passing a sentinel as the first argument
to ranges::next and ranges::prev, which expect an iterator as their
first argument.  In distance.cc we're passing a sentinel as the first
argument to ranges::distance, which also expects an iterator as its
first argument.

Here's an updated patch that adjusts these tests in the straightforward
way.  In test04() in next.cc I had to reset the bounds on the container
after doing ranges::next(begin, end) since we're manipulating an
input_iterator_wrapper.

Is this OK to commit?

-- >8 --

Subject: [PATCH] libstdc++: Always return a sentinel from
 __gnu_test::test_range::end()

It seems that in practice std::sentinel_for is always true, and so the
test_range container doesn't help us detect bugs in ranges code in which we
wrongly assume that a sentinel can be manipulated like an iterator.  Make the
test_range range more strict by having end() unconditionally return a
sentinel, and adjust some tests accordingly.

libstdc++-v3/ChangeLog:

* testsuite/24_iterators/range_operations/distance.cc: Do not assume
test_range::end() returns the same type as test_range::begin().
* testsuite/24_iterators/range_operations/next.cc: Likewise.
* testsuite/24_iterators/range_operations/prev.cc: Likewise.
* testsuite/util/testsuite_iterators.h (__gnu_test::test_range::end):
Always return a sentinel.
---
 .../24_iterators/range_operations/distance.cc | 30 ++
 .../24_iterators/range_operations/next.cc | 57 ++-
 .../24_iterators/range_operations/prev.cc | 50 
 .../testsuite/util/testsuite_iterators.h  |  5 +-
 4 files changed, 78 insertions(+), 64 deletions(-)

diff --git a/libstdc++-v3/testsuite/24_iterators/range_operations/distance.cc 
b/libstdc++-v3/testsuite/24_iterators/range_operations/distance.cc
index 754c0cc200b..cf251b04ec5 100644
--- a/libstdc++-v3/testsuite/24_iterators/range_operations/distance.cc
+++ b/libstdc++-v3/testsuite/24_iterators/range_operations/distance.cc
@@ -39,13 +39,17 @@ test01()
   test_range c(a);
   VERIFY( std::ranges::distance(c) == 10 );

-  auto b = c.begin(), e = c.end();
+  auto b = c.begin();
+  auto e = c.end();
+  auto ei = std::ranges::next(b, e);
   VERIFY( std::ranges::distance(b, e) == 10 );
-  VERIFY( std::ranges::distance(e, b) == -10 );
+  VERIFY( std::ranges::distance(ei, b) == -10 );

-  const auto cb = b, ce = e;
+  const auto cb = b;
+  const auto ce = e;
+  const auto cei = ei;
   VERIFY( std::ranges::distance(cb,

[PATCH] contrib/vimrc: detect more C-like files

2020-02-03 Thread Patrick Palka
Currently this script doesn't set the indentation style for the standard library
headers under libstdc++/ because they lack a file extension.  But they do
have a modeline, so the file type is still set appropriately by Vim.  So by
inspecting &filetype, we can also detect these standard library headers as
C-like files.

contrib/ChangeLog:

* vimrc (SetStyle): Also look at &filetype to determine whether to
a file is C-like.
---
 contrib/vimrc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/contrib/vimrc b/contrib/vimrc
index bbbe1dd449b..e2ccbe0fd10 100644
--- a/contrib/vimrc
+++ b/contrib/vimrc
@@ -39,7 +39,7 @@ function! SetStyle()
   setlocal formatoptions-=ro formatoptions+=cqlt
   let l:ext = fnamemodify(l:fname, ":e")
   let l:c_exts = ['c', 'h', 'cpp', 'cc', 'C', 'H', 'def', 'java']
-  if index(l:c_exts, l:ext) != -1
+  if index(l:c_exts, l:ext) != -1 || &filetype == "cpp" || &filetype == "c"
 setlocal cindent
 setlocal cinoptions=>4,n-2,{2,^-2,:2,=2,g0,f0,h2,p4,t0,+2,(0,u0,w1,m0
   endif
-- 
2.25.0.114.g5b0ca878e0



[PATCH 1/3] libstdc++: Apply the move_iterator changes described in P1207R4

2020-02-03 Thread Patrick Palka
These changes are needed for some of the tests in the constrained algorithm
patch, because they use move_iterator with an uncopyable output_iterator.  The
other changes described in the paper are already applied, it seems.

libstdc++-v3/ChangeLog:

* include/bits/stl_iterator.h (move_iterator::move_iterator): Move the
iterator when initializing _M_current.
(move_iterator::base): Split into two overloads differing in
ref-qualifiers as in P1207R4.
---
 libstdc++-v3/include/bits/stl_iterator.h | 11 +--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/libstdc++-v3/include/bits/stl_iterator.h 
b/libstdc++-v3/include/bits/stl_iterator.h
index 784d200d22f..1a288a5c785 100644
--- a/libstdc++-v3/include/bits/stl_iterator.h
+++ b/libstdc++-v3/include/bits/stl_iterator.h
@@ -1166,7 +1166,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   explicit _GLIBCXX17_CONSTEXPR
   move_iterator(iterator_type __i)
-  : _M_current(__i) { }
+  : _M_current(std::move(__i)) { }
 
   template
_GLIBCXX17_CONSTEXPR
@@ -1174,9 +1174,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: _M_current(__i.base()) { }
 
   _GLIBCXX17_CONSTEXPR iterator_type
-  base() const
+  base() const &
+#if __cplusplus > 201703L && __cpp_lib_concepts
+   requires copy_constructible
+#endif
   { return _M_current; }
 
+  _GLIBCXX17_CONSTEXPR iterator_type
+  base() &&
+  { return std::move(_M_current); }
+
   _GLIBCXX17_CONSTEXPR reference
   operator*() const
   { return static_cast(*_M_current); }
-- 
2.25.0.114.g5b0ca878e0



[PATCH 3/3] libstdc++: Implement C++20 range adaptors

2020-02-03 Thread Patrick Palka
This patch implements [range.adaptors].  It also includes the changes from P3280
and P3278 and P3323, without which many standard examples won't work.

The implementation is mostly dictated by the spec and there was not much room
for implementation discretion.  The most interesting part that was not specified
by the spec is the design of the range adaptors and range adaptor closures,
which I tried to design in a way that minimizes boilerplate and statefulness (so
that e.g. the composition of two stateless closures is stateless).

What is left unimplemented is caching of calls to begin() in filter_view,
drop_view and reverse_view, which is required to guarantee that begin() has
amortized constant time complexity.  I can implement this in a subsequent patch.

"Interesting" parts of the patch are marked with XXX comments.

libstdc++-v3/ChangeLog:

Implement C++20 range adaptors
* include/std/ranges: Include .
(subrange::_S_store_size): Mark as const instead of constexpr to
avoid what seems to be a bug in GCC.
(__detail::__box): Give it defaulted copy and move constructors.
(views::_Single::operator()): Mark constexpr.
(views::_Iota::operator()): Mark constexpr.
(__detail::Empty): Define.
(views::_RangeAdaptor, views::_RangeAdaptorClosure, ref_view, all_view,
views::all, filter_view, views::filter, transform_view,
views::transform, take_view, views::take, take_while_view,
views::take_while, drop_view, views::drop, join_view, views::join,
__detail::require_constant, __detail::tiny_range, split_view,
views::split, views::_Counted, views::counted, common_view,
views::common, reverse_view, views::reverse,
views::__detail::__is_reversible_subrange,
views::__detail::__is_reverse_view, reverse_view, views::reverse,
__detail::__has_tuple_element, elements_view, views::elements,
views::keys, views::values): Define.
* testsuite/std/ranges/adaptors/all.cc: New test.
* testsuite/std/ranges/adaptors/common.cc: Likewise.
* testsuite/std/ranges/adaptors/counted.cc: Likewise.
* testsuite/std/ranges/adaptors/drop.cc: Likewise.
* testsuite/std/ranges/adaptors/drop_while.cc: Likewise.
* testsuite/std/ranges/adaptors/elements.cc: Likewise.
* testsuite/std/ranges/adaptors/filter.cc: Likewise.
* testsuite/std/ranges/adaptors/join.cc: Likewise.
* testsuite/std/ranges/adaptors/reverse.cc: Likewise.
* testsuite/std/ranges/adaptors/split.cc: Likewise.
* testsuite/std/ranges/adaptors/take.cc: Likewise.
* testsuite/std/ranges/adaptors/take_while.cc: Likewise.
* testsuite/std/ranges/adaptors/transform.cc: Likewise.
---
 libstdc++-v3/include/std/ranges   | 2415 -
 .../testsuite/std/ranges/adaptors/all.cc  |  124 +
 .../testsuite/std/ranges/adaptors/common.cc   |   68 +
 .../testsuite/std/ranges/adaptors/counted.cc  |   64 +
 .../testsuite/std/ranges/adaptors/drop.cc |  107 +
 .../std/ranges/adaptors/drop_while.cc |   63 +
 .../testsuite/std/ranges/adaptors/elements.cc |   52 +
 .../testsuite/std/ranges/adaptors/filter.cc   |   97 +
 .../testsuite/std/ranges/adaptors/join.cc |  112 +
 .../testsuite/std/ranges/adaptors/reverse.cc  |   86 +
 .../testsuite/std/ranges/adaptors/split.cc|   82 +
 .../testsuite/std/ranges/adaptors/take.cc |   95 +
 .../std/ranges/adaptors/take_while.cc |   62 +
 .../std/ranges/adaptors/transform.cc  |   86 +
 14 files changed, 3509 insertions(+), 4 deletions(-)
 create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/all.cc
 create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/common.cc
 create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/counted.cc
 create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/drop.cc
 create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/drop_while.cc
 create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/elements.cc
 create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/filter.cc
 create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/join.cc
 create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/reverse.cc
 create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/split.cc
 create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/take.cc
 create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/take_while.cc
 create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc

diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index ea558c76c9d..947e223f7f9 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -39,6 +39,7 @@
 #if __cpp_lib_concepts
 
 #include 
+#include  // std::ref
 #include 
 #include 
 #include 
@@ -255,7 +256,8 @@ namespace ranges
 class subrange : public view_interface>
 {
 priv

Re: [PATCH 1/3] libstdc++: Apply the move_iterator changes described in P1207R4

2020-02-04 Thread Patrick Palka
On Tue, 4 Feb 2020, Jonathan Wakely wrote:

> On 03/02/20 21:07 -0500, Patrick Palka wrote:
> > These changes are needed for some of the tests in the constrained algorithm
> > patch, because they use move_iterator with an uncopyable output_iterator.
> > The
> > other changes described in the paper are already applied, it seems.
> > 
> > libstdc++-v3/ChangeLog:
> > 
> > * include/bits/stl_iterator.h (move_iterator::move_iterator): Move the
> > iterator when initializing _M_current.
> > (move_iterator::base): Split into two overloads differing in
> > ref-qualifiers as in P1207R4.
> > ---
> > libstdc++-v3/include/bits/stl_iterator.h | 11 +--
> > 1 file changed, 9 insertions(+), 2 deletions(-)
> > 
> > diff --git a/libstdc++-v3/include/bits/stl_iterator.h
> > b/libstdc++-v3/include/bits/stl_iterator.h
> > index 784d200d22f..1a288a5c785 100644
> > --- a/libstdc++-v3/include/bits/stl_iterator.h
> > +++ b/libstdc++-v3/include/bits/stl_iterator.h
> > @@ -1166,7 +1166,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> > 
> >   explicit _GLIBCXX17_CONSTEXPR
> >   move_iterator(iterator_type __i)
> > -  : _M_current(__i) { }
> > +  : _M_current(std::move(__i)) { }
> > 
> >   template
> > _GLIBCXX17_CONSTEXPR
> > @@ -1174,9 +1174,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> > : _M_current(__i.base()) { }
> > 
> >   _GLIBCXX17_CONSTEXPR iterator_type
> > -  base() const
> > +  base() const &
> > +#if __cplusplus > 201703L && __cpp_lib_concepts
> > +   requires copy_constructible
> > +#endif
> >   { return _M_current; }
> > 
> > +  _GLIBCXX17_CONSTEXPR iterator_type
> > +  base() &&
> > +  { return std::move(_M_current); }
> > +
> 
> I think this change has to be restricted to C++20 and later, otherwise
> a move_iterator in C++17 can change state so that its _M_current
> becomes moved-from, which should not be possible before C++20.
> 
> So something like:
> 
> #if __cplusplus <= 201703L
>   _GLIBCXX17_CONSTEXPR iterator_type
>   base() const
>   { return _M_current; }
> #else
>   constexpr iterator_type
>   base() const &
> #if __cpp_lib_concepts
>   requires copy_constructible
> #endif
>   { return _M_current; }
> 
>   constexpr iterator_type
>   base() &&
>   { return std::move(_M_current); }
> #endif
> 
> 

Thanks for the review, here is the updated patch.

libstdc++-v3/ChangeLog:

* include/bits/stl_iterator.h (move_iterator::move_iterator): Move __i
when initializing _M_current.
(move_iterator::base): Split into two overloads differing in
ref-qualifiers as in P1207R4 for C++20.
---
 libstdc++-v3/include/bits/stl_iterator.h | 15 ++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/bits/stl_iterator.h 
b/libstdc++-v3/include/bits/stl_iterator.h
index 784d200d22f..c200f7a9d14 100644
--- a/libstdc++-v3/include/bits/stl_iterator.h
+++ b/libstdc++-v3/include/bits/stl_iterator.h
@@ -1166,16 +1166,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   explicit _GLIBCXX17_CONSTEXPR
   move_iterator(iterator_type __i)
-  : _M_current(__i) { }
+  : _M_current(std::move(__i)) { }
 
   template
_GLIBCXX17_CONSTEXPR
move_iterator(const move_iterator<_Iter>& __i)
: _M_current(__i.base()) { }
 
+#if __cplusplus <= 201703L
   _GLIBCXX17_CONSTEXPR iterator_type
   base() const
   { return _M_current; }
+#else
+  constexpr iterator_type
+  base() const &
+#if __cpp_lib_concepts
+   requires copy_constructible
+#endif
+  { return _M_current; }
+
+  constexpr iterator_type
+  base() &&
+  { return std::move(_M_current); }
+#endif
 
   _GLIBCXX17_CONSTEXPR reference
   operator*() const
-- 
2.25.0.114.g5b0ca878e0



Re: [PATCH 2/3] libstdc++: Implement C++20 constrained algorithms

2020-02-05 Thread Patrick Palka
[resending with attachment now compressed]

On Wed, 5 Feb 2020, François Dumont wrote:

> Hi
> 
>     Is it me or the patch isn't an attachment ? It is far more convenient to
> provide something easy to extract and apply locally.

Good point, I've attached the patch as an attachment and I'll make sure
to provide big patches as an attachment in the future.  I should also
have noted that the patches are also available in my user branch
libstdcxx-constrained-algo-adaptors which you can fetch with

git fetch origin 
refs/users/ppalka/heads/libstdcxx-constrained-algos-adaptors

> 
> On 2/4/20 3:07 AM, Patrick Palka wrote:
> > This patch implements the C++20 ranges overloads for the algorithms in
> > [algorithms].  Most of the algorithms were reimplemented, with each of their
> > implementations very closely following the existing implementation in
> > bits/stl_algo.h and bits/stl_algobase.h.  The reason for reimplementing most
> > of
> > the algorithms instead of forwarding to their STL-style overload is because
> > forwarding cannot be conformantly and efficiently performed for algorithms
> > that
> > operate on non-random-access iterators.  But algorithms that operate on
> > random
> > access iterators can safely and efficiently be forwarded to the STL-style
> > implementation, and this patch does so for push_heap, pop_heap, make_heap,
> > sort_heap, sort, stable_sort, nth_element, inplace_merge and
> > stable_partition.
> > 
> > What's missing from this patch is debug-iterator
> 
> Always the 5th wheel of the car like we say in French :-)
> 
> I'll be looking at this point once I manage to apply the patch.

That would be much appreciated! :)

> 
> >   and container specializations
> > that are present for some of the STL-style algorithms that need to be ported
> > over to the ranges algos.  I marked them missing at TODO comments.  There
> > are
> > also some other minor outstanding TODOs.
> > 
> > The code that could use the most thorough review is ranges::__copy_or_move,
> > ranges::__copy_or_move_backward, ranges::__equal and
> > ranges::__lexicographical_compare.  In the tests, I tried to test the
> > interface
> > of each new overload, as well as the correctness of the new implementation.
> > 
> > diff --git a/libstdc++-v3/include/bits/ranges_algo.h
> > b/libstdc++-v3/include/bits/ranges_algo.h
> > new file mode 100644
> > index 000..2e177ce7f7a
> > --- /dev/null
> > +++ b/libstdc++-v3/include/bits/ranges_algo.h
> > @@ -0,0 +1,3640 @@
> > +// Core algorithmic facilities -*- C++ -*-
> > +
> > +// Copyright (C) 2019-2020 Free Software Foundation, Inc.
> 
> Copyright for new files is wrong, should be only 2020. I know it is painful to
> maintain that when you work on patch on several years.

Thanks, fixed!

> 
> > 
> > +//
> > +// This file is part of the GNU ISO C++ Library.  This library 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.
> > +
> > +// This library 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.
> > +
> > +// Under Section 7 of GPL version 3, you are granted additional
> > +// permissions described in the GCC Runtime Library Exception, version
> > +// 3.1, as published by the Free Software Foundation.
> > +
> > +// You should have received a copy of the GNU General Public License and
> > +// a copy of the GCC Runtime Library Exception along with this program;
> > +// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
> > +// <http://www.gnu.org/licenses/>.
> > +
> > +/** @file bits/ranges_algo.h
> > + *  This is an internal header file, included by other library headers.
> > + *  Do not attempt to use it directly. @headername{algorithm}
> > + */
> > +
> > +#ifndef _RANGES_ALGO_H
> > +#define _RANGES_ALGO_H 1
> > +
> > +#if __cplusplus > 201703L
> > +
> > +#include 
> > +#include 
> > +#include 
> > +// #include 
> > +#include 
> > +#include 
> > +#include  // __is_byte
> > +#include  // concept uniform_random_bit_generator
> > +
> > +#if __cpp_lib_concepts
> > +namespace std _GLIBCXX_VISIBILITY(default)
> > +{
> 

Re: [PATCH 3/3] libstdc++: Implement C++20 range adaptors

2020-02-06 Thread Patrick Palka
On Thu, 6 Feb 2020, Jonathan Wakely wrote:

> On 03/02/20 21:07 -0500, Patrick Palka wrote:
> > This patch implements [range.adaptors].  It also includes the changes from
> > P3280
> > and P3278 and P3323, without which many standard examples won't work.
> > 
> > The implementation is mostly dictated by the spec and there was not much
> > room
> > for implementation discretion.  The most interesting part that was not
> > specified
> > by the spec is the design of the range adaptors and range adaptor closures,
> > which I tried to design in a way that minimizes boilerplate and statefulness
> > (so
> > that e.g. the composition of two stateless closures is stateless).
> > 
> > What is left unimplemented is caching of calls to begin() in filter_view,
> > drop_view and reverse_view, which is required to guarantee that begin() has
> > amortized constant time complexity.  I can implement this in a subsequent
> > patch.
> > 
> > "Interesting" parts of the patch are marked with XXX comments.
> 
> 
> 
> > --- a/libstdc++-v3/include/std/ranges
> > +++ b/libstdc++-v3/include/std/ranges
> > @@ -39,6 +39,7 @@
> > #if __cpp_lib_concepts
> > 
> > #include 
> > +#include  // std::ref
> 
> Please use  instead.  is huge.

Fixed.

> 
> > #include 
> > #include 
> > #include 
> > +
> > +namespace __detail
> > +{
> > +  struct _Empty { };
> > +} // namespace __detail
> > +
> > +namespace views
> > +{
> > +  template
> > +struct _RangeAdaptorClosure;
> > +
> > +  template
> > +struct _RangeAdaptor
> > +{
> > +protected:
> > +  [[no_unique_address]]
> > +   conditional_t,
> > + _Callable, __detail::_Empty> _M_callable;
> > +
> > +public:
> > +  constexpr
> > +  _RangeAdaptor(const _Callable& = {})
> > +   requires is_default_constructible_v<_Callable>
> > +  { }
> > +
> > +  constexpr
> > +  _RangeAdaptor(_Callable __callable)
> 
> As mentioned on IRC, the non-explicit constructors here make me
> nervous. I'd either like them to be explicit, or for these typesto be
> in their own namespace so that there is never a reason to attempt
> implicit conversions to them just because some function related to
> them is found in an associated namespace.

Fixed by quarantining these classes into the namespace __adaptor.

> 
> > +   requires (!is_default_constructible_v<_Callable>)
> > +   : _M_callable(std::move(__callable))
> > +  { }
> > +
> 
> 
> 
> 
> > +  template<__detail::__not_same_as _Tp>
> > +   requires convertible_to<_Tp, _Range&>
> > + && requires { _S_fun(declval<_Tp>()); }
> > +   constexpr
> > +   ref_view(_Tp&& __t)
> > + : _M_r(addressof(static_cast<_Range&>(std::forward<_Tp>(__t
> 
> This should be std-qualified to avoid ADL, and should use the internal
> std::__addressof function (just to avoid the extra call from
> std::addressof).

Fixed, for good measure I replaced every call to addressof with
std::__addressof.

> 
> > +  // XXX: the following algos are copied verbatim from ranges_algo.h to
> > avoid a
> > +  // circular dependency with that header.
> 
> Ugh, that's unfortunate, but OK.
> 
> I guess we could put the body of the functions in new, unconstrained
> functions, and then have the ones in  and these
> call those, to reuse the implementations. But they're so small and
> simple it's probably not worth it.

Yeah, I suppose not given their simplicity.

> 
> > +  namespace __detail
> > +  {
> > +template _Sent,
> > +typename _Proj = identity,
> > +indirect_unary_predicate> _Pred>
> > +  constexpr _Iter
> > +  find_if(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {})
> > +  {
> > +   while (__first != __last
> > +   && !(bool)std::__invoke(__pred, std::__invoke(__proj, *__first)))
> > + ++__first;
> > +   return __first;
> > +  }
> > +
> > +template > +indirect_unary_predicate, _Proj>>
> > +  _Pred>
> > +  constexpr safe_iterator_t<_Range>
> > +  find_if(_Range&& __r, _Pred __pred, _Proj __proj = {})
> > +  {
> > +   return __detail::find_if(ranges::begin(__r), ranges::end(__r),
> > +std::move(__pred), std::move(__proj));
> > +  }
>

[PATCH 4/3] Add [range.istream]

2020-02-06 Thread Patrick Palka
This patch adds ranges::basic_istream_view and ranges::istream_view.  This seems
to be the last missing part of the ranges header.

libstdc++-v3/ChangeLog:

* include/std/ranges (ranges::__detail::__stream_extractable,
ranges::basic_istream_view, ranges::istream_view): Define.
* testsuite/std/ranges/istream_view: New test.
---
 libstdc++-v3/include/std/ranges   | 94 +++
 .../testsuite/std/ranges/istream_view.cc  | 76 +++
 2 files changed, 170 insertions(+)
 create mode 100644 libstdc++-v3/testsuite/std/ranges/istream_view.cc

diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 8a8fefb6f19..88b98310ef9 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -951,6 +951,100 @@ namespace views
   inline constexpr _Iota iota{};
 } // namespace views
 
+  namespace __detail
+  {
+template
+  concept __stream_extractable
+   = requires(basic_istream<_CharT, _Traits>& is, _Val& t) { is >> t; };
+  } // namespace __detail
+
+  template
+requires default_initializable<_Val>
+  && __detail::__stream_extractable<_Val, _CharT, _Traits>
+class basic_istream_view
+: public view_interface>
+{
+public:
+  basic_istream_view() = default;
+
+  constexpr explicit
+  basic_istream_view(basic_istream<_CharT, _Traits>& __stream)
+   : _M_stream(std::__addressof(__stream))
+  { }
+
+  constexpr auto
+  begin()
+  {
+   if (_M_stream != nullptr)
+ *_M_stream >> _M_object;
+   return _Iterator{*this};
+  }
+
+  constexpr default_sentinel_t
+  end() const noexcept
+  { return default_sentinel; }
+
+private:
+  basic_istream<_CharT, _Traits>* _M_stream = nullptr;
+  _Val _M_object = _Val();
+
+  struct _Iterator
+  {
+  public:
+   using iterator_category = input_iterator_tag;
+   using difference_type = ptrdiff_t;
+   using value_type = _Val;
+
+   _Iterator() = default;
+
+   constexpr explicit
+   _Iterator(basic_istream_view& __parent) noexcept
+ : _M_parent(std::__addressof(__parent))
+   { }
+
+   _Iterator(const _Iterator&) = delete;
+   _Iterator(_Iterator&&) = default;
+   _Iterator& operator=(const _Iterator&) = delete;
+   _Iterator& operator=(_Iterator&&) = default;
+
+   _Iterator&
+   operator++()
+   {
+ __glibcxx_assert(_M_parent->_M_stream != nullptr);
+ *_M_parent->_M_stream >> _M_parent->_M_object;
+   }
+
+   void
+   operator++(int)
+   { ++*this; }
+
+   _Val&
+   operator*() const
+   {
+ __glibcxx_assert(_M_parent->_M_stream != nullptr);
+ return _M_parent->_M_object;
+   }
+
+   friend bool
+   operator==(const _Iterator& __x, default_sentinel_t)
+   { return __x.__at_end(); }
+
+  private:
+   basic_istream_view* _M_parent = nullptr;
+
+   bool
+   __at_end() const
+   { return _M_parent == nullptr || !*_M_parent->_M_stream; }
+  };
+
+  friend _Iterator;
+};
+
+  template
+basic_istream_view<_Val, _CharT, _Traits>
+istream_view(basic_istream<_CharT, _Traits>& __s)
+{ return basic_istream_view<_Val, _CharT, _Traits>{__s}; }
+
 namespace __detail
 {
   struct _Empty { };
diff --git a/libstdc++-v3/testsuite/std/ranges/istream_view.cc 
b/libstdc++-v3/testsuite/std/ranges/istream_view.cc
new file mode 100644
index 000..c573ba57ae8
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/ranges/istream_view.cc
@@ -0,0 +1,76 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library 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.
+
+// This library 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 this library; see the file COPYING3.  If not see
+// .
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+namespace ranges = std::ranges;
+namespace views = std::views;
+
+struct X : __gnutest::rvalstruct
+{
+  char c;
+
+  friend std::istream&
+  operator>>(std::istream& is, X& m)
+  {
+is >> m.c;
+return is;
+  }
+};
+
+
+void
+test01()
+{
+  std::string s = "0123456789";
+  auto ss = std::istringstream{s};
+  auto v = ranges::istream_view(ss) | views::transform(&X::c);
+  VERIFY( ranges::equal(v, s) );
+}
+
+void
+test02()
+{
+  auto ints = std::istringstream{"0 1  2

Re: [PATCH 2/3] libstdc++: Implement C++20 constrained algorithms

2020-02-06 Thread Patrick Palka
On Thu, 6 Feb 2020, Jonathan Wakely wrote:

> On 03/02/20 21:07 -0500, Patrick Palka wrote:
> > +#ifndef _RANGES_ALGO_H
> > +#define _RANGES_ALGO_H 1
> > +
> > +#if __cplusplus > 201703L
> > +
> > +#include 
> > +#include 
> > +#include 
> > +// #include 
> 
> This line could be removed, or leave it as a reminder to me to
> refactor  so that the small utility pieces are in a small
> utility header (like  that can be included
> instead of the whole of .

I guess I'll leave it in then.

> 
> > +#include 
> > +#include 
> > +#include  // __is_byte
> > +#include  // concept uniform_random_bit_generator
> 
> I wonder if we want to move that concept to 
> instead, which already exists to allow  to avoid including
> the whole of . If we do that, it would make sense to rename
>  to  or something like
> that.

That makes sense -- I can try to do that in a followup patch.

> 
> > +
> > +#if __cpp_lib_concepts
> > +namespace std _GLIBCXX_VISIBILITY(default)
> > +{
> > +_GLIBCXX_BEGIN_NAMESPACE_VERSION
> > +namespace ranges
> > +{
> > +  namespace __detail
> > +  {
> > +template
> > +constexpr inline bool __is_normal_iterator = false;
> 
> All these templates in the __detail namespace should be indented by
> two spaces after the template-head i.e.
> 
> template
>   constexpr inline bool __is_normal_iterator = false;
> 
> (That indentation scheme has been in the libstdc++ style guide for
> longer than I've been contributing to the project, but it doesn't seem
> very popular with new contributors, and it wastes a level of
> indentation for templates, which means most of the library. Maybe we
> should revisit that convention.)

Fixed

> 
> 
> > +  template
> > +using unary_transform_result = copy_result<_Iter, _Out>;
> > +
> > +  template _Sent,
> > +  weakly_incrementable _Out,
> > +  copy_constructible _Fp, typename _Proj = identity>
> > +requires writable<_Out, indirect_result_t<_Fp&, projected<_Iter,
> > _Proj>>>
> 
> I have a pending patch to implement P1878R1, which renames writable
> (and a few other concepts). I'll wait until your patch is in, and
> change these places using it.

Sounds good.

> 
> > +partial_sort_copy(_Iter1 __first, _Sent1 __last,
> > + _Iter2 __result_first, _Sent2 __result_last,
> > + _Comp __comp = {},
> > + _Proj1 __proj1 = {}, _Proj2 __proj2 = {})
> > +{
> > +  if (__result_first == __result_last)
> > +   {
> > + // TODO: Eliminating the variable __lasti triggers an ICE.
> > + auto __lasti = ranges::next(std::move(__first),
> > + std::move(__last));
> > + return {std::move(__lasti), std::move(__result_first)};
> 
> Please try to reduce that and report it to bugzilla at some point,
> thanks.

Will do!  Interestingly, it was an ICE in the middle-end.  I wasn't able
to reproduce it anymore, but I'll try more carefully tomorrow.

> 
> > +++ b/libstdc++-v3/testsuite/25_algorithms/all_of/constrained.cc
> > @@ -0,0 +1,90 @@
> > +// Copyright (C) 2019 Free Software Foundation, Inc.
> 
> This should be 2020. That's the only change necessary though, please
> adjust that and commit to master. Great work, thank you!

Fixed.  Thank you for the review!  Patch committed, hopefully without
any fallout.



Re: [PATCH 3/3] libstdc++: Implement C++20 range adaptors

2020-02-07 Thread Patrick Palka
On Fri, 7 Feb 2020, Jonathan Wakely wrote:

> On 06/02/20 18:53 -0500, Patrick Palka wrote:
> > On Thu, 6 Feb 2020, Jonathan Wakely wrote:
> > > > +#ifdef __cpp_lib_threeway_comparison
> > > 
> > > This macro is mispelled, should be three_way with an underscore.
> > 
> > Oops!  It looks like it's also mispelled in the definition of iota_view
> > earlier in this file.
> 
> Oops, yes, my fault then. Fixed with this patch, tested
> powerpc64le-linux and committed to master. I've reported the defect
> with the return types to the LWG chair.
> 
> Your incremental changes look good, please squash them into the base
> patch and push that to master. Thanks.

Thanks for the review.  I just committed the squashed version after a
successful regtest.



Re: [PATCH 4/3] Add [range.istream]

2020-02-07 Thread Patrick Palka
On Fri, 7 Feb 2020, Jonathan Wakely wrote:

> On 06/02/20 19:52 -0500, Patrick Palka wrote:
> > This patch adds ranges::basic_istream_view and ranges::istream_view.  This
> > seems
> > to be the last missing part of the ranges header.
> > 
> > libstdc++-v3/ChangeLog:
> > 
> > * include/std/ranges (ranges::__detail::__stream_extractable,
> > ranges::basic_istream_view, ranges::istream_view): Define.
> > * testsuite/std/ranges/istream_view: New test.
> > ---
> > libstdc++-v3/include/std/ranges   | 94 +++
> > .../testsuite/std/ranges/istream_view.cc  | 76 +++
> > 2 files changed, 170 insertions(+)
> > create mode 100644 libstdc++-v3/testsuite/std/ranges/istream_view.cc
> > 
> > diff --git a/libstdc++-v3/include/std/ranges
> > b/libstdc++-v3/include/std/ranges
> > index 8a8fefb6f19..88b98310ef9 100644
> > --- a/libstdc++-v3/include/std/ranges
> > +++ b/libstdc++-v3/include/std/ranges
> > @@ -951,6 +951,100 @@ namespace views
> >   inline constexpr _Iota iota{};
> > } // namespace views
> > 
> > +  namespace __detail
> > +  {
> > +template
> > +  concept __stream_extractable
> > +   = requires(basic_istream<_CharT, _Traits>& is, _Val& t) { is >> t; };
> 
> I was going to ask for "is" and "t" to use reserved names, but those
> names are actually reserved. std::ctype::is is present since C++98 and
> std::binomial_distribution::t() since C++11. So the names are OK.

Phew! :)  I just forgot to uglify those names.

> 
> > +  } // namespace __detail
> > +
> > +  template
> > +requires default_initializable<_Val>
> > +  && __detail::__stream_extractable<_Val, _CharT, _Traits>
> > +class basic_istream_view
> > +: public view_interface>
> > +{
> > +public:
> > +  basic_istream_view() = default;
> > +
> > +  constexpr explicit
> > +  basic_istream_view(basic_istream<_CharT, _Traits>& __stream)
> > +   : _M_stream(std::__addressof(__stream))
> > +  { }
> > +
> > +  constexpr auto
> > +  begin()
> > +  {
> > +   if (_M_stream != nullptr)
> > + *_M_stream >> _M_object;
> > +   return _Iterator{*this};
> > +  }
> > +
> > +  constexpr default_sentinel_t
> > +  end() const noexcept
> > +  { return default_sentinel; }
> > +
> > +private:
> > +  basic_istream<_CharT, _Traits>* _M_stream = nullptr;
> > +  _Val _M_object = _Val();
> > +
> > +  struct _Iterator
> > +  {
> > +  public:
> > +   using iterator_category = input_iterator_tag;
> > +   using difference_type = ptrdiff_t;
> > +   using value_type = _Val;
> > +
> > +   _Iterator() = default;
> > +
> > +   constexpr explicit
> > +   _Iterator(basic_istream_view& __parent) noexcept
> > + : _M_parent(std::__addressof(__parent))
> > +   { }
> > +
> > +   _Iterator(const _Iterator&) = delete;
> > +   _Iterator(_Iterator&&) = default;
> > +   _Iterator& operator=(const _Iterator&) = delete;
> > +   _Iterator& operator=(_Iterator&&) = default;
> > +
> > +   _Iterator&
> > +   operator++()
> > +   {
> > + __glibcxx_assert(_M_parent->_M_stream != nullptr);
> > + *_M_parent->_M_stream >> _M_parent->_M_object;
> > +   }
> > +
> > +   void
> > +   operator++(int)
> > +   { ++*this; }
> > +
> > +   _Val&
> > +   operator*() const
> > +   {
> > + __glibcxx_assert(_M_parent->_M_stream != nullptr);
> > + return _M_parent->_M_object;
> > +   }
> > +
> > +   friend bool
> > +   operator==(const _Iterator& __x, default_sentinel_t)
> > +   { return __x.__at_end(); }
> > +
> > +  private:
> > +   basic_istream_view* _M_parent = nullptr;
> > +
> > +   bool
> > +   __at_end() const
> 
> Please rename this to _M_at_end for consistency with the rest of the
> library.
> 
> OK for master with that tweak, thanks.

Fixed and committed with that change.  Thanks for the review!



[PATCH] libstdc++: Make sure iterator_traits is populated

2020-02-07 Thread Patrick Palka
Since basic_istream_view::iterator is neither a cpp17 iterator (because it's
move-only) nor does it define all four of the types {difference_type,
value_type, reference, iterator_category}, then by the rule in
[iterator.traits], its iterator_traits has no members.

More concretely this means that it can't e.g. be composed with a
views::transform or a views::filter because they look at the iterator_traits of
the underlying view.

This seems to be a defect in the current spec.

libstdc++-v3/ChangeLog:

* include/std/ranges (ranges::basic_istream_view::iterator::reference):
Define it so that this iterator's iterator_traits is populated.
* testsuite/std/ranges/istream_view.cc: Augment test.
---
 libstdc++-v3/include/std/ranges   |  1 +
 libstdc++-v3/testsuite/std/ranges/istream_view.cc | 11 +++
 2 files changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 891ecf75eff..6e982d6ded3 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -996,6 +996,7 @@ namespace views
using iterator_category = input_iterator_tag;
using difference_type = ptrdiff_t;
using value_type = _Val;
+   using reference = _Val&;
 
_Iterator() = default;
 
diff --git a/libstdc++-v3/testsuite/std/ranges/istream_view.cc 
b/libstdc++-v3/testsuite/std/ranges/istream_view.cc
index 1729459bce3..7feb3ff4b0a 100644
--- a/libstdc++-v3/testsuite/std/ranges/istream_view.cc
+++ b/libstdc++-v3/testsuite/std/ranges/istream_view.cc
@@ -68,10 +68,21 @@ test03()
   VERIFY( ranges::equal(v, (int[]){0,1,2,3,4}) );
 }
 
+void
+test04()
+{
+  std::string s = "0123456789";
+  auto ss = std::istringstream{s};
+  static_assert(ranges::input_range(ss))>);
+  auto v = ranges::istream_view(ss) | views::transform(&X::c);
+  VERIFY( ranges::equal(v, s) );
+}
+
 int
 main()
 {
   test01();
   test02();
   test03();
+  test04();
 }
-- 
2.25.0.191.gde93cc14ab



[PATCH] c++: Fix return type deduction with an abbreviated function template

2020-02-10 Thread Patrick Palka
This patch fixes two issues with return type deduction in the presence of an
abbreviated function template.

The first issue (PR 69448) is that if a placeholder auto return type contains
any modifiers such as & or *, then the abbreviated-function-template
compensation in splice_late_return_type does not get performed for the
underlying auto node, leading to incorrect return type deduction.  This happens
because splice_late_return_type checks for a placeholder auto with is_auto,
which does not look through modifiers.  This patch replaces the use of is_auto
with find_type_usage, but it first refactors find_type_usage to return a pointer
to the matched tree so that we next subsequently replace it.

The second issue (PR 80471) is that the AUTO_IS_DECLTYPE flag is not being
preserved in splice_late_return_type when compensating for an abbreviated
function template, leading to us treating a decltype(auto) return type as if it
was an auto return type.  Fixed by propagating AUTO_IS_DECLTYPE.  The test for
PR 80471 is adjusted to expect the correct behavior.

Bootstrapped and regtested on x86_64-pc-linux-gnu, is this OK to commit?

gcc/cp/ChangeLog:

PR c++/69448
PR c++/80471
* type-utils.h (find_type_usage): Refactor to take a tree * and to
return a tree *, and update documentation accordingly.
* pt.c (splice_late_return_type): Use find_type_usage to find and
replace a possibly nested auto node.  Preserve the AUTO_IS_DECLTYPE
flag when replacing the node.
(type_uses_auto): Adjust the call to find_type_usage.

gcc/testsuite/ChangeLog:

PR c++/69448
PR c++/80471
* g++.dg/concepts/abbrev3.C: New test.
* g++.dg/cpp2a/concepts-pr80471.C: Adjust a static_assert to expect the
correct behavior.
---
 gcc/cp/pt.c   | 26 ---
 gcc/cp/type-utils.h   | 26 +--
 gcc/testsuite/g++.dg/concepts/abbrev3.C   | 11 
 gcc/testsuite/g++.dg/cpp2a/concepts-pr80471.C |  2 +-
 4 files changed, 41 insertions(+), 24 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/concepts/abbrev3.C

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 2fb52caa5d4..c83aaa7c7e1 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -28904,17 +28904,21 @@ do_auto_deduction (tree type, tree init, tree 
auto_node,
 tree
 splice_late_return_type (tree type, tree late_return_type)
 {
-  if (is_auto (type))
-{
-  if (late_return_type)
-   return late_return_type;
+  if (is_auto (type) && late_return_type)
+return late_return_type;
 
-  tree idx = get_template_parm_index (type);
+  if (tree *auto_node = find_type_usage (&type, is_auto))
+{
+  tree idx = get_template_parm_index (*auto_node);
   if (TEMPLATE_PARM_LEVEL (idx) <= processing_template_decl)
-   /* In an abbreviated function template we didn't know we were dealing
-  with a function template when we saw the auto return type, so update
-  it to have the correct level.  */
-   return make_auto_1 (TYPE_IDENTIFIER (type), true);
+   {
+ /* In an abbreviated function template we didn't know we were dealing
+with a function template when we saw the auto return type, so
+update it to have the correct level.  */
+ tree new_node = make_auto_1 (TYPE_IDENTIFIER (*auto_node), true);
+ AUTO_IS_DECLTYPE (new_node) = AUTO_IS_DECLTYPE (*auto_node);
+ *auto_node = new_node;
+   }
 }
   return type;
 }
@@ -28960,8 +28964,10 @@ type_uses_auto (tree type)
   else
return NULL_TREE;
 }
+  else if (tree *tp = find_type_usage (&type, is_auto))
+return *tp;
   else
-return find_type_usage (type, is_auto);
+return NULL_TREE;
 }
 
 /* Report ill-formed occurrences of auto types in ARGUMENTS.  If
diff --git a/gcc/cp/type-utils.h b/gcc/cp/type-utils.h
index 680b2497a36..4ad0d822119 100644
--- a/gcc/cp/type-utils.h
+++ b/gcc/cp/type-utils.h
@@ -20,36 +20,36 @@ along with GCC; see the file COPYING3.  If not see
 #ifndef GCC_CP_TYPE_UTILS_H
 #define GCC_CP_TYPE_UTILS_H
 
-/* Returns the first tree within T that is directly matched by PRED.  T may be 
a
-   type or PARM_DECL and is incrementally decomposed toward its type-specifier
-   until a match is found.  NULL_TREE is returned if PRED does not match any
-   part of T.
+/* Returns a pointer to the first tree within *TP that is directly matched by
+   PRED.  *TP may be a type or PARM_DECL and is incrementally decomposed toward
+   its type-specifier until a match is found.  NULL is returned if PRED does 
not
+   match any part of *TP.
 
-   This is primarily intended for detecting whether T uses `auto' or a concept
+   This is primarily intended for detecting whether *TP uses `auto' or a 
concept
identifier.  Since either of these can only appear as a type-specifier for
the declaration in question, only top-level qualifications are traversed;

Re: [PATCH] libstdc++: Make sure iterator_traits is populated

2020-02-10 Thread Patrick Palka
On Mon, 10 Feb 2020, Jonathan Wakely wrote:

> On 07/02/20 13:59 -0500, Patrick Palka wrote:
> > Since basic_istream_view::iterator is neither a cpp17 iterator (because it's
> > move-only) nor does it define all four of the types {difference_type,
> > value_type, reference, iterator_category}, then by the rule in
> > [iterator.traits], its iterator_traits has no members.
> > 
> > More concretely this means that it can't e.g. be composed with a
> > views::transform or a views::filter because they look at the iterator_traits
> > of
> > the underlying view.
> > 
> > This seems to be a defect in the current spec.
> 
> Agreed, but Casey Carter doesn't think this fix is correct, as it
> would make this iterator appear to be a Cpp17InputIterator, which is
> unwanted.
> 
> Please don't make this change, we should wait for guidance from LWG.

Sounds good.



[PATCH] c++: Improve dump_decl for standard concepts

2020-02-10 Thread Patrick Palka
This patch improves the pretty printing of standard concept definitions in error
messages.  In particular, standard concepts are now printed qualified whenever
appropriate, and the "concept" specifier is printed only when the
TFF_DECL_SPECIFIERS flag is specified.

In the below test, the first error message changes from
  9:15: error: ‘b’ was not declared in this scope; did you mean ‘concept b’?
to
  9:15: error: ‘b’ was not declared in this scope; did you mean ‘a::b’?

Tested on x86_64-pc-linux-gnu, is this OK to commit?

gcc/cp/ChangeLog:

* error.c (dump_decl) [CONCEPT_DECL]: Use dump_simple_decl.
(dump_simple_decl): Handle standard concept definitions as well as
variable concept definitions.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts6.C: New test.
---
 gcc/cp/error.c | 18 --
 gcc/testsuite/g++.dg/cpp2a/concepts6.C | 18 ++
 2 files changed, 26 insertions(+), 10 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts6.C

diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 973b3034e12..a56d83e1f45 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -1037,14 +1037,13 @@ dump_simple_decl (cxx_pretty_printer *pp, tree t, tree 
type, int flags)
 
   if (flags & TFF_DECL_SPECIFIERS)
 {
-  if (VAR_P (t) && DECL_DECLARED_CONSTEXPR_P (t))
-{
- if (DECL_LANG_SPECIFIC (t) && DECL_DECLARED_CONCEPT_P (t))
-   pp_cxx_ws_string (pp, "concept");
- else
-   pp_cxx_ws_string (pp, "constexpr");
-   }
-  dump_type_prefix (pp, type, flags & ~TFF_UNQUALIFIED_NAME);
+  if (concept_definition_p (t))
+   pp_cxx_ws_string (pp, "concept");
+  else if (VAR_P (t) && DECL_DECLARED_CONSTEXPR_P (t))
+   pp_cxx_ws_string (pp, "constexpr");
+
+  if (!standard_concept_p (t))
+   dump_type_prefix (pp, type, flags & ~TFF_UNQUALIFIED_NAME);
   pp_maybe_space (pp);
 }
   if (! (flags & TFF_UNQUALIFIED_NAME)
@@ -1296,8 +1295,7 @@ dump_decl (cxx_pretty_printer *pp, tree t, int flags)
   break;
 
 case CONCEPT_DECL:
-  pp_cxx_ws_string (pp, "concept");
-  dump_decl_name (pp, DECL_NAME (t), flags);
+  dump_simple_decl (pp, t, TREE_TYPE (t), flags);
   break;
 
 case WILDCARD_DECL:
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts6.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts6.C
new file mode 100644
index 000..d69628b0318
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts6.C
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++2a } }
+
+namespace a
+{
+  template
+concept b = true; // { dg-message ".a::b. declared here" }
+}
+
+static_assert(b); // { dg-error "did you mean .a::b." }
+
+namespace c
+{
+  template
+concept b = true; // { dg-message "concept c::b." }
+
+  template
+concept b = true; // { dg-error "concept c::b." }
+}
-- 
2.25.0.191.gde93cc14ab



Re: [PATCH] c++: Fix return type deduction with an abbreviated function template

2020-02-10 Thread Patrick Palka
On Mon, 10 Feb 2020, Jason Merrill wrote:

> On 2/10/20 2:20 PM, Patrick Palka wrote:
> > This patch fixes two issues with return type deduction in the presence of an
> > abbreviated function template.
> > 
> > The first issue (PR 69448) is that if a placeholder auto return type
> > contains
> > any modifiers such as & or *, then the abbreviated-function-template
> > compensation in splice_late_return_type does not get performed for the
> > underlying auto node, leading to incorrect return type deduction.  This
> > happens
> > because splice_late_return_type checks for a placeholder auto with is_auto,
> > which does not look through modifiers.  This patch replaces the use of
> > is_auto
> > with find_type_usage, but it first refactors find_type_usage to return a
> > pointer
> > to the matched tree so that we next subsequently replace it.
> > 
> > The second issue (PR 80471) is that the AUTO_IS_DECLTYPE flag is not being
> > preserved in splice_late_return_type when compensating for an abbreviated
> > function template, leading to us treating a decltype(auto) return type as if
> > it
> > was an auto return type.  Fixed by propagating AUTO_IS_DECLTYPE.  The test
> > for
> > PR 80471 is adjusted to expect the correct behavior.
> 
> The comment in make_constrained_decltype_auto suggests that we should set
> AUTO_IS_DECLTYPE in make_auto_1 if name == decltype_auto_identifier; then
> callers won't need to worry about it.

Updated the patch to make_auto_1 to set AUTO_IS_DECLTYPE when
appropriate, and adjusted callers accordingly.  Now make_auto_1 is the
only place where we set AUTO_IS_DECLTYPE.

> 
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, is this OK to commit?
> > 
> > gcc/cp/ChangeLog:
> > 
> > PR c++/69448
> > PR c++/80471
> > * type-utils.h (find_type_usage): Refactor to take a tree * and to
> > return a tree *, and update documentation accordingly.
> > * pt.c (splice_late_return_type): Use find_type_usage to find and
> > replace a possibly nested auto node.  Preserve the AUTO_IS_DECLTYPE
> > flag when replacing the node.
> > (type_uses_auto): Adjust the call to find_type_usage.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > PR c++/69448
> > PR c++/80471
> > * g++.dg/concepts/abbrev3.C: New test.
> > * g++.dg/cpp2a/concepts-pr80471.C: Adjust a static_assert to expect
> > the
> > correct behavior.
> > ---
> >   gcc/cp/pt.c   | 26 ---
> >   gcc/cp/type-utils.h   | 26 +--
> >   gcc/testsuite/g++.dg/concepts/abbrev3.C   | 11 
> >   gcc/testsuite/g++.dg/cpp2a/concepts-pr80471.C |  2 +-
> >   4 files changed, 41 insertions(+), 24 deletions(-)
> >   create mode 100644 gcc/testsuite/g++.dg/concepts/abbrev3.C
> > 
> > diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> > index 2fb52caa5d4..c83aaa7c7e1 100644
> > --- a/gcc/cp/pt.c
> > +++ b/gcc/cp/pt.c
> > @@ -28904,17 +28904,21 @@ do_auto_deduction (tree type, tree init, tree
> > auto_node,
> >   tree
> >   splice_late_return_type (tree type, tree late_return_type)
> >   {
> > -  if (is_auto (type))
> > -{
> > -  if (late_return_type)
> > -   return late_return_type;
> > +  if (is_auto (type) && late_return_type)
> > +return late_return_type;
> 
> It occurs to me that we could just check late_return_type here, maybe change
> the is_auto test to an assert.

Done -- I had to add a seen_error test to the assert to accomodate error
recovery and also adjust a dg-error directive in g++.dg/cpp0x/auto9.C.
Does this version look OK after testing?

-- >8 --

gcc/cp/ChangeLog:

PR c++/69448
PR c++/80471
* type-utils.h (find_type_usage): Refactor to take a tree * and to
return a tree *, and update documentation accordingly.
* pt.c (make_auto_1): Set AUTO_IS_DECLTYPE when building a
decltype(auto) node.
(make_constrained_decltype_auto): No need to explicitly set
AUTO_IS_DECLTYPE anymore.
(splice_late_return_type): Use find_type_usage to find and
replace a possibly nested auto node instead of using is_auto.
Check test for is_auto into an assert when deciding whether
to late_return_type.
(type_uses_auto): Adjust the call to find_type_usage.
* parser.c (cp_parser_decltype): No need to explicitly set
AUTO_IS_DECLTYPE anymore.

gcc/libcc1/ChangeLog:

* libcp1plugin.cc (plugin_get_expr_type): No need to explicitly set
AUTO_IS_DE

[PATCH] libstdc++: Fix LWG issues 3389 and 3390

2020-02-11 Thread Patrick Palka
libstdc++-v3/ChangeLog:

DR 3389 and DR 3390
* include/bits/stl_iterator.h (move_move_iterator): Use std::move when
constructing the move_iterator with __i.
(counted_iterator::counted_iterator): Use std::move when initializing
M_current with __i.
* testsuite/24_iterators/counted_iterator/dr3389.cc: New test.
* testsuite/24_iterators/move_iterator/dr3390.cc: New test.
---
 libstdc++-v3/include/bits/stl_iterator.h  |  4 +-
 .../24_iterators/counted_iterator/dr3389.cc   | 66 +++
 .../24_iterators/move_iterator/dr3390.cc  | 66 +++
 3 files changed, 134 insertions(+), 2 deletions(-)
 create mode 100644 
libstdc++-v3/testsuite/24_iterators/counted_iterator/dr3389.cc
 create mode 100644 libstdc++-v3/testsuite/24_iterators/move_iterator/dr3390.cc

diff --git a/libstdc++-v3/include/bits/stl_iterator.h 
b/libstdc++-v3/include/bits/stl_iterator.h
index 4e70672924b..fc9d442b475 100644
--- a/libstdc++-v3/include/bits/stl_iterator.h
+++ b/libstdc++-v3/include/bits/stl_iterator.h
@@ -1375,7 +1375,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template
 inline _GLIBCXX17_CONSTEXPR move_iterator<_Iterator>
 make_move_iterator(_Iterator __i)
-{ return move_iterator<_Iterator>(__i); }
+{ return move_iterator<_Iterator>(std::move(__i)); }
 
   template __n)
-  : _M_current(__i), _M_length(__n)
+  : _M_current(std::move(__i)), _M_length(__n)
   { __glibcxx_assert(__n >= 0); }
 
   template
diff --git a/libstdc++-v3/testsuite/24_iterators/counted_iterator/dr3389.cc 
b/libstdc++-v3/testsuite/24_iterators/counted_iterator/dr3389.cc
new file mode 100644
index 000..c72317407cd
--- /dev/null
+++ b/libstdc++-v3/testsuite/24_iterators/counted_iterator/dr3389.cc
@@ -0,0 +1,66 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library 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.
+
+// This library 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 this library; see the file COPYING3.  If not see
+// .
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include 
+
+#include 
+
+using __gnu_test::test_range;
+using __gnu_test::input_iterator_wrapper;
+
+template
+struct move_only_wrapper : input_iterator_wrapper
+{
+  using input_iterator_wrapper::input_iterator_wrapper;
+
+  move_only_wrapper()
+: input_iterator_wrapper(nullptr, nullptr)
+  { }
+
+  move_only_wrapper(const move_only_wrapper&) = delete;
+  move_only_wrapper&
+  operator=(const move_only_wrapper&) = delete;
+
+  move_only_wrapper(move_only_wrapper&&) = default;
+  move_only_wrapper&
+  operator=(move_only_wrapper&&) = default;
+
+  using input_iterator_wrapper::operator++;
+
+  move_only_wrapper&
+  operator++()
+  {
+input_iterator_wrapper::operator++();
+return *this;
+  }
+};
+
+static_assert(std::input_iterator>);
+static_assert(!std::forward_iterator>);
+static_assert(!std::copyable>);
+
+// DR 3390
+void
+test01()
+{
+  int x[] = {1,2,3,4};
+  test_range rx(x);
+  auto it = std::counted_iterator(rx.begin(), 2);
+}
diff --git a/libstdc++-v3/testsuite/24_iterators/move_iterator/dr3390.cc 
b/libstdc++-v3/testsuite/24_iterators/move_iterator/dr3390.cc
new file mode 100644
index 000..100d68c1d5e
--- /dev/null
+++ b/libstdc++-v3/testsuite/24_iterators/move_iterator/dr3390.cc
@@ -0,0 +1,66 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library 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.
+
+// This library 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 this library; see the file COPYING3.  If not see
+// .
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include 
+
+#include 
+
+using __gnu_test::test_range;
+using __gnu_test::input_iterator_wrapper;
+
+template
+struct move_only_wrapper : input_iterator_wrapper
+{
+  using input_iterator_wrapper::input_iterator_wrapper;
+
+  move_only_wr

Re: [PATCH] libstdc++: Fix LWG issues 3389 and 3390

2020-02-11 Thread Patrick Palka
On Tue, 11 Feb 2020, Patrick Palka wrote:

> libstdc++-v3/ChangeLog:
> 
>   DR 3389 and DR 3390
>   * include/bits/stl_iterator.h (move_move_iterator): Use std::move when
>   constructing the move_iterator with __i.
>   (counted_iterator::counted_iterator): Use std::move when initializing
>   M_current with __i.
>   * testsuite/24_iterators/counted_iterator/dr3389.cc: New test.
>   * testsuite/24_iterators/move_iterator/dr3390.cc: New test.

Here's a version of the patch that uses the consistently uses the
terminology LWG  instead of sometimes using DR .

-- >8 --

Subject: [PATCH] libstdc++: Fix LWG issues 3389 and 3390

libstdc++-v3/ChangeLog:

LWG 3389 and LWG 3390
* include/bits/stl_iterator.h (move_move_iterator): Use std::move when
constructing the move_iterator with __i.
(counted_iterator::counted_iterator): Use std::move when initializing
M_current with __i.
* testsuite/24_iterators/counted_iterator/lwg3389.cc: New test.
* testsuite/24_iterators/move_iterator/lwg3390.cc: New test.
---
 libstdc++-v3/include/bits/stl_iterator.h  |  4 +-
 .../24_iterators/counted_iterator/lwg3389.cc  | 66 +++
 .../24_iterators/move_iterator/lwg3390.cc | 66 +++
 3 files changed, 134 insertions(+), 2 deletions(-)
 create mode 100644 
libstdc++-v3/testsuite/24_iterators/counted_iterator/lwg3389.cc
 create mode 100644 libstdc++-v3/testsuite/24_iterators/move_iterator/lwg3390.cc

diff --git a/libstdc++-v3/include/bits/stl_iterator.h 
b/libstdc++-v3/include/bits/stl_iterator.h
index 4e70672924b..fc9d442b475 100644
--- a/libstdc++-v3/include/bits/stl_iterator.h
+++ b/libstdc++-v3/include/bits/stl_iterator.h
@@ -1375,7 +1375,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template
 inline _GLIBCXX17_CONSTEXPR move_iterator<_Iterator>
 make_move_iterator(_Iterator __i)
-{ return move_iterator<_Iterator>(__i); }
+{ return move_iterator<_Iterator>(std::move(__i)); }
 
   template __n)
-  : _M_current(__i), _M_length(__n)
+  : _M_current(std::move(__i)), _M_length(__n)
   { __glibcxx_assert(__n >= 0); }
 
   template
diff --git a/libstdc++-v3/testsuite/24_iterators/counted_iterator/lwg3389.cc 
b/libstdc++-v3/testsuite/24_iterators/counted_iterator/lwg3389.cc
new file mode 100644
index 000..cf74fd47bec
--- /dev/null
+++ b/libstdc++-v3/testsuite/24_iterators/counted_iterator/lwg3389.cc
@@ -0,0 +1,66 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library 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.
+
+// This library 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 this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include 
+
+#include 
+
+using __gnu_test::test_range;
+using __gnu_test::input_iterator_wrapper;
+
+template
+struct move_only_wrapper : input_iterator_wrapper
+{
+  using input_iterator_wrapper::input_iterator_wrapper;
+
+  move_only_wrapper()
+: input_iterator_wrapper(nullptr, nullptr)
+  { }
+
+  move_only_wrapper(const move_only_wrapper&) = delete;
+  move_only_wrapper&
+  operator=(const move_only_wrapper&) = delete;
+
+  move_only_wrapper(move_only_wrapper&&) = default;
+  move_only_wrapper&
+  operator=(move_only_wrapper&&) = default;
+
+  using input_iterator_wrapper::operator++;
+
+  move_only_wrapper&
+  operator++()
+  {
+input_iterator_wrapper::operator++();
+return *this;
+  }
+};
+
+static_assert(std::input_iterator>);
+static_assert(!std::forward_iterator>);
+static_assert(!std::copyable>);
+
+// LWG 3389
+void
+test01()
+{
+  int x[] = {1,2,3,4};
+  test_range rx(x);
+  auto it = std::counted_iterator(rx.begin(), 2);
+}
diff --git a/libstdc++-v3/testsuite/24_iterators/move_iterator/lwg3390.cc 
b/libstdc++-v3/testsuite/24_iterators/move_iterator/lwg3390.cc
new file mode 100644
index 000..1df7caccece
--- /dev/null
+++ b/libstdc++-v3/testsuite/24_iterators/move_iterator/lwg3390.cc
@@ -0,0 +1,66 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library 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; eithe

[PATCH] libstdc++: Memoize {drop,drop_while,filter,reverse}_view::begin

2020-02-11 Thread Patrick Palka
This patch adds memoization for these four views so that their begin() has the
required constant time amortized complexity.

In the general case we use std::optional to cache the result.  When the
underlying range is a random_access_range then we store the cache as an offset
from the beginning of the range, which should be more compact.  And when the
underlying iterator is not copyable, then we completely disable the cache.

Using std::optional in the cache is not ideal though because it means that the
cache can't be utilized during constexpr evaluation.  If instead of
std::optional we store a separate flag to denote an empty cache then we'll be
able to use the cache during constexpr evaluation at the cost of a extra byte or
so.  I am not sure which design to settle on.

libstdc++-v3/ChangeLog:

* include/std/ranges (__detail::_CachedPosition): New.
(views::filter_view::_S_needs_cached_begin): New member variable.
(views::filter_view::_M_cached_begin): New member variable.
(views::filter_view::begin): Use _M_cached_begin to cache its
result.
(views::drop_view::_S_needs_cached_begin): New static member variable.
(views::drop_view::_M_cached_begin): New member variable.
(views::drop_view::begin): Use _M_cached_begin to cache its result
when _S_needs_cached_begin.
(views::drop_while_view::_M_cached_begin): New member variable.
(views::drop_while_view::begin): Use _M_cached_begin to cache its
result.
(views::reverse_view::_S_needs_cached_begin): New static member
variable.
(views::reverse_view::_M_cached_begin): New member variable.
(views::reverse_view::begin): Use _M_cached_begin to cache its result
when _S_needs_cached_begin.
* testsuite/std/ranges/adaptors/drop.cc: Augment test to check that
drop_view::begin caches its result.
* testsuite/std/ranges/adaptors/drop_while.cc: Augment test to check
that drop_while_view::begin caches its result.
* testsuite/std/ranges/adaptors/filter.cc: Augment test to check that
filter_view::begin caches its result.
* testsuite/std/ranges/adaptors/reverse.cc: Augment test to check that
reverse_view::begin caches its result.
---
 libstdc++-v3/include/std/ranges   | 138 --
 .../testsuite/std/ranges/adaptors/drop.cc |  57 
 .../std/ranges/adaptors/drop_while.cc |  38 -
 .../testsuite/std/ranges/adaptors/filter.cc   |  36 +
 .../testsuite/std/ranges/adaptors/reverse.cc  |  56 +++
 5 files changed, 310 insertions(+), 15 deletions(-)

diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index ef613175b7c..485a073ad3a 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -1302,6 +1302,83 @@ namespace views
   }
   } // namespace __detail
 
+  namespace __detail
+  {
+template
+  struct _CachedPosition
+  {
+  private:
+   std::optional> _M_iter;
+
+  public:
+   constexpr bool
+   _M_has_value() const
+   { return _M_iter.has_value(); }
+
+   constexpr iterator_t<_Range>
+   _M_get(const _Range&) const
+   {
+ __glibcxx_assert(_M_has_value());
+ return *_M_iter;
+   }
+
+   constexpr void
+   _M_set(const _Range&, const iterator_t<_Range>& __it)
+   {
+ __glibcxx_assert(!_M_has_value());
+ if constexpr (copyable>)
+   if (!is_constant_evaluated())
+ _M_iter.emplace(__it);
+   }
+  };
+
+template
+  struct _CachedPosition<_Range>
+  {
+  private:
+   range_difference_t<_Range> _M_offset = -1;
+
+  public:
+   constexpr bool
+   _M_has_value() const
+   { return _M_offset >= 0; }
+
+   constexpr iterator_t<_Range>
+   _M_get(_Range& __r) const
+   {
+ __glibcxx_assert(_M_has_value());
+ return ranges::begin(__r) + _M_offset;
+   }
+
+   constexpr void
+   _M_set(_Range& __r, const iterator_t<_Range>& __it)
+   {
+ __glibcxx_assert(!_M_has_value());
+ _M_offset = __it - ranges::begin(__r);
+   }
+  };
+
+template
+  requires (!copyable>)
+  struct _CachedPosition<_Range>
+  {
+   constexpr bool
+   _M_has_value() const
+   { return false; }
+
+   constexpr iterator_t<_Range>
+   _M_get(const _Range&) const
+   {
+ __glibcxx_assert(false);
+ return {};
+   }
+
+   constexpr void
+   _M_set(const _Range&, const iterator_t<_Range>&) const
+   { }
+  };
+  } // namespace __detail
+
   template> _Pred>
 requires view<_Vp> && is_object_v<_Pred>
@@ -1457,6 +1534,7 @@ namespace views
 
   _Vp _M_base = _Vp();
   __detail::__box<_Pred> _M_pred;
+  [[no_unique_address]] __detail::_CachedPosition<_Vp> _M_cached_begin;
 
 public:
   filter_view() = default;
@@

[PATCH] c++: Fix hashing and testing for equality of ATOMIC_CONST_EXPRs

2020-02-12 Thread Patrick Palka
Two equal atomic constraint expressions do not necessarily share the same tree,
so we can't assume that two ATOMIC_CONST_EXPRs are equal if and only if they
point to the same tree.  The main consequence of this invalid assumption is that
the constraint subsumption checker may reject a valid partial specialization for
a constrained template because the checker decides that the constraints on the
partial specialization do not subsume the constraints on the primary template,
as in the test case below.  Another consequence is that it probably makes the
constraint caches less effective.

This patch changes atomic_constraints_identical_p to test for equality of
ATOMIC_CONST_EXPRs using cp_tree_equal, and changes hash_atomic_constraint to
hash the ATOMIC_CONST_EXPR with iterative_hash_template_arg.  Originally I used
template_args_equal but cp_tree_equal seems to suffice.

Does this look like an OK solution to this issue?  Are the testcase adjustments
valid?

gcc/cp/ChangeLog:

* constraint.cc (atomic_constraints_identical_p): Use cp_tree_equal to
test for equality between ATOMIC_CONST_EXPRs.
(hash_atomic_constraint): Use iterative_hash_template to hash the
ATOMIC_CONST_EXPR.

gcc/testsuite/ChangeLog:

* g++.dg/concepts/variadic4.C: Adjust test to no longere expect an
error.
* g++.dg/cpp2a/concepts-pr84551.C: Likewise.
* g++.dg/cpp2a/concepts-partial-spec7.C: New test.
---
 gcc/cp/constraint.cc  |  4 +-
 gcc/testsuite/g++.dg/concepts/variadic4.C |  4 +-
 .../g++.dg/cpp2a/concepts-partial-spec7.C | 40 +++
 gcc/testsuite/g++.dg/cpp2a/concepts-pr84551.C |  2 +-
 4 files changed, 44 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec7.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 58044cd0f9d..935c3556272 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -933,7 +933,7 @@ atomic_constraints_identical_p (tree t1, tree t2)
   gcc_assert (TREE_CODE (t1) == ATOMIC_CONSTR);
   gcc_assert (TREE_CODE (t2) == ATOMIC_CONSTR);
 
-  if (ATOMIC_CONSTR_EXPR (t1) != ATOMIC_CONSTR_EXPR (t2))
+  if (!cp_tree_equal (ATOMIC_CONSTR_EXPR (t1), ATOMIC_CONSTR_EXPR (t2)))
 return false;
 
   if (!parameter_mapping_equivalent_p (t1, t2))
@@ -981,7 +981,7 @@ hash_atomic_constraint (tree t)
   gcc_assert (TREE_CODE (t) == ATOMIC_CONSTR);
 
   /* Hash the identity of the expression.  */
-  hashval_t val = htab_hash_pointer (ATOMIC_CONSTR_EXPR (t));
+  hashval_t val = iterative_hash_template_arg (ATOMIC_CONSTR_EXPR (t), 0);
 
   /* Hash the targets of the parameter map.  */
   tree p = ATOMIC_CONSTR_MAP (t);
diff --git a/gcc/testsuite/g++.dg/concepts/variadic4.C 
b/gcc/testsuite/g++.dg/concepts/variadic4.C
index d6eea49b958..b073bcce5e9 100644
--- a/gcc/testsuite/g++.dg/concepts/variadic4.C
+++ b/gcc/testsuite/g++.dg/concepts/variadic4.C
@@ -12,9 +12,7 @@ struct zip;
 
 template
 requires requires { typename list; } // && (Sequence && ...)
-struct zip {}; // { dg-error "does not specialize" }
-// The constraints of the specialization and the sequence are not
-// comparable; the specializations are unordered.
+struct zip {};
 
 int main()
 {
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec7.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec7.C
new file mode 100644
index 000..ed77ed4d362
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec7.C
@@ -0,0 +1,40 @@
+// { dg-do compile { target c++2a } }
+
+template
+  inline constexpr bool foo = true;
+
+template
+  inline constexpr bool bar = true;
+
+// The following two partial specializations are both valid, but the constraint
+// subsumption checker used to compare ATOMIC_CONSTR_EXPRs by comparing their
+// pointers, leading to it accepting the partial specialization of test1 and
+// rejecting the partial specialization of test2: in the test1 case, the
+// TEMPLATE_ID_EXPR of foo in the constraints was shared between the primary
+// template and partial specialization, and in the test2 case the
+// TEMPLATE_ID_EXPRs of foo in the constraints were different (but equal)
+// trees.
+
+template
+  concept baz = foo;
+
+template
+  requires baz
+  struct test1
+  { };
+
+template
+  requires baz && bar
+  struct test1
+  { };
+
+template
+  requires foo
+  struct test2
+  { };
+
+template
+  requires foo && bar
+  struct test2
+  { };
+
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr84551.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84551.C
index e40796f4975..e7498437178 100644
--- a/gcc/testsuite/g++.dg/cpp2a/concepts-pr84551.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84551.C
@@ -8,4 +8,4 @@ template requires C class TT> struct A 
{};
 
 template requires true struct B {};
 
-A a;// { dg-error "" }
+A a;
-- 
2.25.0.191.gde93cc14ab



[PATCH 1/2] libstdc++: Move some ranges algos to a new header

2020-02-12 Thread Patrick Palka
This roughly mirrors the existing split between  and
.  The ranges [specialized.algorithms] will use this new
header to avoid including all of of .

libstdc++-v3/ChangeLog:

* include/Makefile.am: Add bits/ranges_algobase.h
* include/Makefile.in: Regenerate.
* bits/ranges_algo.h: Include  and refactor
existing #includes.
(__detail::__is_normal_iterator, __detail::is_reverse_iterator,
__detail::__is_move_iterator, copy_result, move_result,
__equal, equal, copy_result, move_result, move_backward_result,
copy_backward_result, __copy_or_move_backward, __copy_or_move, copy,
move, copy_backward, move_backward, copy_n_result, copy_n, fill_n,
fill): Split out into ...
* bits/range_algobase.h: ... this new header.
---
 libstdc++-v3/include/Makefile.am|   1 +
 libstdc++-v3/include/Makefile.in|   1 +
 libstdc++-v3/include/bits/ranges_algo.h | 508 +-
 libstdc++-v3/include/bits/ranges_algobase.h | 556 
 4 files changed, 559 insertions(+), 507 deletions(-)
 create mode 100644 libstdc++-v3/include/bits/ranges_algobase.h

diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index 1d342cecbcc..614222db400 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -157,6 +157,7 @@ bits_headers = \
${bits_srcdir}/random.tcc \
${bits_srcdir}/range_access.h \
${bits_srcdir}/range_cmp.h \
+   ${bits_srcdir}/ranges_algobase.h \
${bits_srcdir}/ranges_algo.h \
${bits_srcdir}/refwrap.h \
${bits_srcdir}/regex.h \
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
index c735d67a5d3..7ee6a1e3f61 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -502,6 +502,7 @@ bits_headers = \
${bits_srcdir}/random.tcc \
${bits_srcdir}/range_access.h \
${bits_srcdir}/range_cmp.h \
+   ${bits_srcdir}/ranges_algobase.h \
${bits_srcdir}/ranges_algo.h \
${bits_srcdir}/refwrap.h \
${bits_srcdir}/regex.h \
diff --git a/libstdc++-v3/include/bits/ranges_algo.h 
b/libstdc++-v3/include/bits/ranges_algo.h
index e065ff2a974..84a02cabb80 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -32,13 +32,7 @@
 
 #if __cplusplus > 201703L
 
-#include 
-#include 
-#include 
-// #include 
-#include 
-#include 
-#include  // __is_byte
+#include 
 #include  // concept uniform_random_bit_generator
 
 #if __cpp_lib_concepts
@@ -49,28 +43,6 @@ namespace ranges
 {
   namespace __detail
   {
-template
-  constexpr inline bool __is_normal_iterator = false;
-
-template
-  constexpr inline bool
-   __is_normal_iterator<__gnu_cxx::__normal_iterator<_Iterator,
- _Container>> = true;
-
-template
-  constexpr inline bool __is_reverse_iterator = false;
-
-template
-  constexpr inline bool
-   __is_reverse_iterator> = true;
-
-template
-  constexpr inline bool __is_move_iterator = false;
-
-template
-  constexpr inline bool
-   __is_move_iterator> = true;
-
 template
   constexpr auto
   __make_comp_proj(_Comp& __comp, _Proj& __proj)
@@ -741,420 +713,6 @@ namespace ranges
std::move(__proj1), std::move(__proj2));
 }
 
-  template _Sent1,
-  input_iterator _Iter2, sentinel_for<_Iter2> _Sent2,
-  typename _Pred, typename _Proj1, typename _Proj2>
-requires indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2>
-constexpr bool
-__equal(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2,
-   _Pred __pred, _Proj1 __proj1, _Proj2 __proj2)
-{
-  // TODO: implement more specializations to at least have parity with
-  // std::equal.
-  constexpr bool __sized_iters
-   = (sized_sentinel_for<_Sent1, _Iter1>
-  && sized_sentinel_for<_Sent2, _Iter2>);
-  if constexpr (__sized_iters)
-   {
- auto __d1 = ranges::distance(__first1, __last1);
- auto __d2 = ranges::distance(__first2, __last2);
- if (__d1 != __d2)
-   return false;
-
- using _ValueType1 = iter_value_t<_Iter1>;
- using _ValueType2 = iter_value_t<_Iter2>;
- constexpr bool __use_memcmp
-   = ((is_integral_v<_ValueType1> || is_pointer_v<_ValueType1>)
-  && is_same_v<_ValueType1, _ValueType2>
-  && is_pointer_v<_Iter1>
-  && is_pointer_v<_Iter2>
-  && is_same_v<_Pred, ranges::equal_to>
-  && is_same_v<_Proj1, identity>
-  && is_same_v<_Proj2, identity>);
- if constexpr (__use_memcmp)
-   {
- if (const size_t __len = (__last1 - __first1))
-   return !std::__memcmp(__first1, __first2, __len);
-   

[PATCH 2/2] libstdc++: Implement ranges [specialized.algorithms]

2020-02-12 Thread Patrick Palka
This implements all the ranges members defined in [specialized.algorithms]:

  ranges::uninitialized_default_construct
  ranges::uninitialized_value_construct
  ranges::uninitialized_copy
  ranges::uninitialized_copy_n
  ranges::uninitialized_move
  ranges::uninitialized_move_n
  ranges::uninitialized_fill
  ranges::uninitialized_fill_n
  ranges::construct_at
  ranges::destroy_at
  ranges::destroy

It also implements (hopefully correctly) the "obvious" optimizations for these
algos, namely that if the output range has a trivial value type and if the
appropriate operation won't throw then we can dispatch to the standard ranges
version of the algorithm which will then potentially enable further
optimizations.

libstdc++-v3/ChangeLog:

* include/Makefile.am: Add .
* include/Makefile.in: Regenerate.
* include/bits/ranges_uninitialized.h: New header.
* include/std/memory: Include it.
* testsuite/20_util/specialized_algorithms/destroy/constrained.cc: New
test.
* .../uninitialized_copy/constrained.cc: New test.
* .../uninitialized_default_construct/constrained.cc: New test.
* .../uninitialized_fill/constrained.cc: New test.
* .../uninitialized_move/constrained.cc: New test.
* .../uninitialized_value_construct/constrained.cc: New test.
---
 libstdc++-v3/include/Makefile.am  |   1 +
 libstdc++-v3/include/Makefile.in  |   1 +
 .../include/bits/ranges_uninitialized.h   | 491 ++
 libstdc++-v3/include/std/memory   |   1 +
 .../destroy/constrained.cc|  76 +++
 .../uninitialized_copy/constrained.cc | 166 ++
 .../constrained.cc| 147 ++
 .../uninitialized_fill/constrained.cc | 137 +
 .../uninitialized_move/constrained.cc | 176 +++
 .../constrained.cc| 140 +
 10 files changed, 1336 insertions(+)
 create mode 100644 libstdc++-v3/include/bits/ranges_uninitialized.h
 create mode 100644 
libstdc++-v3/testsuite/20_util/specialized_algorithms/destroy/constrained.cc
 create mode 100644 
libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/constrained.cc
 create mode 100644 
libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_default_construct/constrained.cc
 create mode 100644 
libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/constrained.cc
 create mode 100644 
libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/constrained.cc
 create mode 100644 
libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_value_construct/constrained.cc

diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index 614222db400..e131ce04f8c 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -159,6 +159,7 @@ bits_headers = \
${bits_srcdir}/range_cmp.h \
${bits_srcdir}/ranges_algobase.h \
${bits_srcdir}/ranges_algo.h \
+   ${bits_srcdir}/ranges_uninitialized.h \
${bits_srcdir}/refwrap.h \
${bits_srcdir}/regex.h \
${bits_srcdir}/regex.tcc \
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
index 7ee6a1e3f61..ae20f6b1d21 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -504,6 +504,7 @@ bits_headers = \
${bits_srcdir}/range_cmp.h \
${bits_srcdir}/ranges_algobase.h \
${bits_srcdir}/ranges_algo.h \
+   ${bits_srcdir}/ranges_uninitialized.h \
${bits_srcdir}/refwrap.h \
${bits_srcdir}/regex.h \
${bits_srcdir}/regex.tcc \
diff --git a/libstdc++-v3/include/bits/ranges_uninitialized.h 
b/libstdc++-v3/include/bits/ranges_uninitialized.h
new file mode 100644
index 000..252295faed7
--- /dev/null
+++ b/libstdc++-v3/include/bits/ranges_uninitialized.h
@@ -0,0 +1,491 @@
+// Raw memory manipulators -*- C++ -*-
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library 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.
+
+// This library 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNT

Re: [PATCH 2/2] libstdc++: Implement ranges [specialized.algorithms]

2020-02-13 Thread Patrick Palka
On Thu, 13 Feb 2020, Jonathan Wakely wrote:

> On 12/02/20 15:41 -0500, Patrick Palka wrote:
> > This implements all the ranges members defined in [specialized.algorithms]:
> > 
> >  ranges::uninitialized_default_construct
> >  ranges::uninitialized_value_construct
> >  ranges::uninitialized_copy
> >  ranges::uninitialized_copy_n
> >  ranges::uninitialized_move
> >  ranges::uninitialized_move_n
> >  ranges::uninitialized_fill
> >  ranges::uninitialized_fill_n
> >  ranges::construct_at
> >  ranges::destroy_at
> >  ranges::destroy
> > 
> > It also implements (hopefully correctly) the "obvious" optimizations for
> > these
> > algos, namely that if the output range has a trivial value type and if the
> > appropriate operation won't throw then we can dispatch to the standard
> > ranges
> > version of the algorithm which will then potentially enable further
> > optimizations.
> > 
> > libstdc++-v3/ChangeLog:
> > 
> > * include/Makefile.am: Add .
> > * include/Makefile.in: Regenerate.
> > * include/bits/ranges_uninitialized.h: New header.
> > * include/std/memory: Include it.
> > * testsuite/20_util/specialized_algorithms/destroy/constrained.cc: New
> > test.
> > * .../uninitialized_copy/constrained.cc: New test.
> > * .../uninitialized_default_construct/constrained.cc: New test.
> > * .../uninitialized_fill/constrained.cc: New test.
> > * .../uninitialized_move/constrained.cc: New test.
> > * .../uninitialized_value_construct/constrained.cc: New test.
> 
> 
> 
> > +  template<__detail::__nothrow_input_iterator _Iter,
> > +  __detail::__nothrow_sentinel<_Iter> _Sent>
> > +requires destructible>
> > +constexpr _Iter
> > +destroy(_Iter __first, _Sent __last) noexcept
> > +{
> > +  if constexpr (is_trivially_destructible_v>)
> > +   return ranges::next(__first, __last);
> > +  else
> > +   {
> > + for (; __first != __last; ++__first)
> > +   ranges::destroy_at(addressof(*__first));
> 
> This should be std::__addressof
> 
> > + return __first;
> > +   }
> > +}
> > +
> > +  template<__detail::__nothrow_input_range _Range>
> > +requires destructible>
> > +constexpr safe_iterator_t<_Range>
> > +destroy(_Range&& __r) noexcept
> > +{ return ranges::destroy(ranges::begin(__r), ranges::end(__r)); }
> > +
> > +  template<__detail::__nothrow_input_iterator _Iter>
> > +requires destructible>
> > +constexpr _Iter
> > +destroy_n(_Iter __first, iter_difference_t<_Iter> __n) noexcept
> > +{
> > +  if constexpr (is_trivially_destructible_v>)
> > +   return ranges::next(__first, __n);
> > +  else
> > +   {
> > + for (; __n > 0; ++__first, (void)--__n)
> > +   ranges::destroy_at(addressof(*__first));
> 
> Same here.
> 
> OK for master with those two adjustments.

Incorporated those two changes and committed both patches.  Thanks for
the review!



Re: [PATCH] c++: Fix hashing and testing for equality of ATOMIC_CONST_EXPRs

2020-02-13 Thread Patrick Palka
On Fri, 14 Feb 2020, Jason Merrill wrote:

> On 2/12/20 5:15 PM, Patrick Palka wrote:
> > Two equal atomic constraint expressions do not necessarily share the same
> > tree,
> > so we can't assume that two ATOMIC_CONST_EXPRs are equal if and only if they
> > point to the same tree.
> 
> This is incorrect; comparison of atomic constraints is based on them coming
> from the same actual tokens, which is why we use pointer comparison.
> 
> In your concepts-partial-spec7.C, test2 is properly rejected.  If you want to
> be able to write the same constraint in multiple places, you need to use a
> concept.
> 
> 13.5.1.2:
> 
> Two atomic constraints are identical if they are formed from the same
> expression and the targets of the parameter mappings are equivalent according
> to the rules for expressions described in 13.7.6.1.

I see, that makes complete sense now.  I was stumbling over what the
spec meant by "the same expression."  Thanks for clearing up my
misunderstanding.



[PATCH 1/3] libstdc++: Fold some ranges algo subroutines into their only caller

2020-02-14 Thread Patrick Palka
These subroutines have only a single call site, so it might be best and simplest
to eliminate them before we convert the algos into function objects.

libstdc++-v3/ChangeLog:

* include/bits/ranges_algo.h (ranges::__find_end): Fold into ...
(ranges::find_end): ... here.
(ranges::__lexicographical_compare): Fold into ...
(ranges::lexicographical_compare): ... here.
* include/bits/ranges_algobase.h (ranges::__equal): Fold into ...
(ranges::equal): ... here.
---
 libstdc++-v3/include/bits/ranges_algo.h | 104 
 libstdc++-v3/include/bits/ranges_algobase.h |  33 +++
 2 files changed, 55 insertions(+), 82 deletions(-)

diff --git a/libstdc++-v3/include/bits/ranges_algo.h 
b/libstdc++-v3/include/bits/ranges_algo.h
index 84a02cabb80..6b6f4defdf5 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -513,40 +513,7 @@ namespace ranges
  std::move(__pred), std::move(__proj));
 }
 
-  template _Sent1,
-  forward_iterator _Iter2, sentinel_for<_Iter2> _Sent2,
-  typename _Pred = ranges::equal_to,
-  typename _Proj1 = identity, typename _Proj2 = identity>
-requires indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2>
-constexpr subrange<_Iter1>
-__find_end(_Iter1 __first1, _Sent1 __last1,
-  _Iter2 __first2, _Sent2 __last2,
-  _Pred __pred, _Proj1 __proj1, _Proj2 __proj2)
-{
-  auto __i = ranges::next(__first1, __last1);
-  if (__first2 == __last2)
-   return {__i, __i};
 
-  auto __result_begin = __i;
-  auto __result_end = __i;
-  for (;;)
-   {
- auto __new_range = ranges::search(__first1, __last1,
-   __first2, __last2,
-   __pred, __proj1, __proj2);
- auto __new_result_begin = ranges::begin(__new_range);
- auto __new_result_end = ranges::end(__new_range);
- if (__new_result_begin == __last1)
-   return {__result_begin, __result_end};
- else
-   {
- __result_begin = __new_result_begin;
- __result_end = __new_result_end;
- __first1 = __result_begin;
- ++__first1;
-   }
-   }
-}
 
   template _Sent1,
   forward_iterator _Iter2, sentinel_for<_Iter2> _Sent2,
@@ -578,9 +545,31 @@ namespace ranges
return {__result_first, __result_last};
}
   else
-   return ranges::__find_end(__first1, __last1, __first2, __last2,
- std::move(__pred),
- std::move(__proj1), std::move(__proj2));
+   {
+ auto __i = ranges::next(__first1, __last1);
+ if (__first2 == __last2)
+   return {__i, __i};
+
+ auto __result_begin = __i;
+ auto __result_end = __i;
+ for (;;)
+   {
+ auto __new_range = ranges::search(__first1, __last1,
+   __first2, __last2,
+   __pred, __proj1, __proj2);
+ auto __new_result_begin = ranges::begin(__new_range);
+ auto __new_result_end = ranges::end(__new_range);
+ if (__new_result_begin == __last1)
+   return {__result_begin, __result_end};
+ else
+   {
+ __result_begin = __new_result_begin;
+ __result_end = __new_result_end;
+ __first1 = __result_begin;
+ ++__first1;
+   }
+   }
+   }
 }
 
   template _Sent1,
   input_iterator _Iter2, sentinel_for<_Iter2> _Sent2,
-  typename _Proj1, typename _Proj2,
+  typename _Proj1 = identity, typename _Proj2 = identity,
   indirect_strict_weak_order,
- projected<_Iter2, _Proj2>> _Comp>
+ projected<_Iter2, _Proj2>>
+_Comp = ranges::less>
 constexpr bool
-__lexicographical_compare(_Iter1 __first1, _Sent1 __last1,
- _Iter2 __first2, _Sent2 __last2,
- _Comp __comp, _Proj1 __proj1, _Proj2 __proj2)
+lexicographical_compare(_Iter1 __first1, _Sent1 __last1,
+   _Iter2 __first2, _Sent2 __last2,
+   _Comp __comp = {},
+   _Proj1 __proj1 = {}, _Proj2 __proj2 = {})
 {
+  if constexpr (__detail::__is_normal_iterator<_Iter1>
+   || __detail::__is_normal_iterator<_Iter2>)
+   return ranges::lexicographical_compare
+(std::__niter_base(std::move(__first1)),
+ std::__niter_base(std::move(__last1)),
+ std::__niter_base(std::move(__first2)),
+ std::__niter_base(std::move(__last2)),
+ s

[PATCH 3/3] libstdc++: Post-conversion whitespace and formatting adjustments

2020-02-14 Thread Patrick Palka
libstdc++-v3/ChangeLog:

* include/bits/ranges_algo.h: Adjust whitespace and formatting.
* include/bits/ranges_algobase.h: Likewise.
* include/bits/ranges_uninitialized.h: Likewise.
---
 libstdc++-v3/include/bits/ranges_algo.h   | 631 ++
 libstdc++-v3/include/bits/ranges_algobase.h   |  39 +-
 .../include/bits/ranges_uninitialized.h   |  38 +-
 3 files changed, 376 insertions(+), 332 deletions(-)

diff --git a/libstdc++-v3/include/bits/ranges_algo.h 
b/libstdc++-v3/include/bits/ranges_algo.h
index af6d1722998..7f8f0fb964b 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -73,7 +73,8 @@ namespace ranges
 typename _Proj = identity,
 indirect_unary_predicate> _Pred>
   constexpr bool
-  operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) 
const
+  operator()(_Iter __first, _Sent __last,
+_Pred __pred, _Proj __proj = {}) const
   {
for (; __first != __last; ++__first)
  if (!(bool)std::__invoke(__pred, std::__invoke(__proj, *__first)))
@@ -82,7 +83,8 @@ namespace ranges
   }
 
 template, _Proj>> 
_Pred>
+indirect_unary_predicate, _Proj>>
+  _Pred>
   constexpr bool
   operator()(_Range&& __r, _Pred __pred, _Proj __proj = {}) const
   {
@@ -99,7 +101,8 @@ namespace ranges
 typename _Proj = identity,
 indirect_unary_predicate> _Pred>
   constexpr bool
-  operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) 
const
+  operator()(_Iter __first, _Sent __last,
+_Pred __pred, _Proj __proj = {}) const
   {
for (; __first != __last; ++__first)
  if (std::__invoke(__pred, std::__invoke(__proj, *__first)))
@@ -108,12 +111,13 @@ namespace ranges
   }
 
 template, _Proj>> 
_Pred>
+indirect_unary_predicate, _Proj>>
+  _Pred>
   constexpr bool
   operator()(_Range&& __r, _Pred __pred, _Proj __proj = {}) const
   {
return (*this)(ranges::begin(__r), ranges::end(__r),
- std::move(__pred), std::move(__proj));
+  std::move(__pred), std::move(__proj));
   }
   };
 
@@ -125,7 +129,8 @@ namespace ranges
 typename _Proj = identity,
 indirect_unary_predicate> _Pred>
   constexpr bool
-  operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) 
const
+  operator()(_Iter __first, _Sent __last,
+_Pred __pred, _Proj __proj = {}) const
   {
for (; __first != __last; ++__first)
  if (std::__invoke(__pred, std::__invoke(__proj, *__first)))
@@ -134,7 +139,8 @@ namespace ranges
   }
 
 template, _Proj>> 
_Pred>
+indirect_unary_predicate, _Proj>>
+  _Pred>
   constexpr bool
   operator()(_Range&& __r, _Pred __pred, _Proj __proj = {}) const
   {
@@ -183,7 +189,7 @@ namespace ranges
   operator()(_Range&& __r, _Fun __f, _Proj __proj = {}) const
   {
return (*this)(ranges::begin(__r), ranges::end(__r),
-   std::move(__f), std::move(__proj));
+  std::move(__f), std::move(__proj));
   }
   };
 
@@ -196,7 +202,8 @@ namespace ranges
   requires indirect_binary_predicate, const _Tp*>
   constexpr _Iter
-  operator()(_Iter __first, _Sent __last, const _Tp& __value, _Proj __proj 
= {}) const
+  operator()(_Iter __first, _Sent __last,
+const _Tp& __value, _Proj __proj = {}) const
   {
while (__first != __last
&& !(std::__invoke(__proj, *__first) == __value))
@@ -211,8 +218,8 @@ namespace ranges
   constexpr safe_iterator_t<_Range>
   operator()(_Range&& __r, const _Tp& __value, _Proj __proj = {}) const
   {
-   return (*this)(ranges::begin(__r), ranges::end(__r), __value,
-   std::move(__proj));
+   return (*this)(ranges::begin(__r), ranges::end(__r),
+  __value, std::move(__proj));
   }
   };
 
@@ -224,7 +231,8 @@ namespace ranges
 typename _Proj = identity,
 indirect_unary_predicate> _Pred>
   constexpr _Iter
-  operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) 
const
+  operator()(_Iter __first, _Sent __last,
+_Pred __pred, _Proj __proj = {}) const
   {
while (__first != __last
&& !(bool)std::__invoke(__pred, std::__invoke(__proj, *__first)))
@@ -239,7 +247,7 @@ namespace ranges
   operator()(_Range&& __r, _Pred __pred, _Proj __proj = {}) const
   {
return (*this)(ranges::begin(__r), ranges::end(__r),
-  std::move(__pred), std::move(__proj));
+  std::move(__pred), std::move(__proj));
   }
   };
 
@@ -251,7 +259,8 @@ namespace ranges
 

[PATCH 2/3] libstdc++: Convert the ranges algorithm entities into function objects

2020-02-14 Thread Patrick Palka
This is the standard way to inhibit ADL for these entities, which is required as
per [algorithms.requirements] p2 and [specialized.algorithms] p4.  The
conversion was done mostly mechanically with a custom Vim macro.

[  To make it easier to review, the diffstat below was generated with the -w
   flag, which ignores all changes to whitespace.  Formatting will be fixed in a
   subsequent patch.  ]

libstdc++-v3/ChangeLog:

* include/bits/ranges_algo.h: (adjacent_find, all_of, any_of,
binary_search, copy_if, count, count_if, equal_range, find, find_end,
find_first_of, find_if, find_if_not, for_each, generate, generate_n,
includes, inplace_merge, is_heap, is_heap_until, is_partitioned,
is_permutation, is_sorted, is_sorted_until, lexicographical_compare,
lower_bound, make_heap, max, max_element, merge, min, min_element,
minmax, minmax_element, mismatch, next_permutation, none_of,
nth_element, partial_sort, partial_sort_copy, partition, partition_copy,
partition_point, pop_heap, prev_permutation, push_heap, remove,
remove_copy, remove_copy_if, remove_if, replace, replace_copy,
replace_copy_if, replace_if, reverse, reverse_copy, rotate, rotate_copy,
search, search_n, set_difference, set_intersection,
set_symmetric_difference, set_union, shuffle, sort, sort_heap,
stable_partition, stable_sort, swap_ranges, transform, unique,
unique_copy, upper_bound): Convert into function objects.
* include/bits/ranges_algobase.h: (equal, copy, move, copy_n, fill_n,
fill, move_backward, copy_backward): Likewise.
* include/bits/ranges_uninitialized.h (uninitialized_default_construct,
uninitialized_default_construct_n, uninitialized_value_construct,
uninitialized_value_construct_n, uninitialized_copy,
uninitialized_copy_n, uninitialized_move, uninitialized_move_n,
uninitialized_fill, uninitialized_fill_n, construct_at, destroy_at,
destroy, destroy_n): Likewise.
---
 libstdc++-v3/include/bits/ranges_algo.h   | 1019 +++--
 libstdc++-v3/include/bits/ranges_algobase.h   |   86 +-
 .../include/bits/ranges_uninitialized.h   |  145 ++-
 3 files changed, 868 insertions(+), 382 deletions(-)

diff --git a/libstdc++-v3/include/bits/ranges_algo.h 
b/libstdc++-v3/include/bits/ranges_algo.h
index 6b6f4defdf5..af6d1722998 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -67,11 +67,13 @@ namespace ranges
   }
   } // namespace __detail
 
+  struct __all_of_fn
+  {
 template _Sent,
 typename _Proj = identity,
 indirect_unary_predicate> _Pred>
   constexpr bool
-all_of(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {})
+  operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) 
const
   {
for (; __first != __last; ++__first)
  if (!(bool)std::__invoke(__pred, std::__invoke(__proj, *__first)))
@@ -82,17 +84,22 @@ namespace ranges
 template, _Proj>> 
_Pred>
   constexpr bool
-all_of(_Range&& __r, _Pred __pred, _Proj __proj = {})
+  operator()(_Range&& __r, _Pred __pred, _Proj __proj = {}) const
   {
-  return ranges::all_of(ranges::begin(__r), ranges::end(__r),
+   return (*this)(ranges::begin(__r), ranges::end(__r),
   std::move(__pred), std::move(__proj));
   }
+  };
+
+  inline constexpr __all_of_fn all_of{};
 
+  struct __any_of_fn
+  {
 template _Sent,
 typename _Proj = identity,
 indirect_unary_predicate> _Pred>
   constexpr bool
-any_of(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {})
+  operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) 
const
   {
for (; __first != __last; ++__first)
  if (std::__invoke(__pred, std::__invoke(__proj, *__first)))
@@ -103,17 +110,22 @@ namespace ranges
 template, _Proj>> 
_Pred>
   constexpr bool
-any_of(_Range&& __r, _Pred __pred, _Proj __proj = {})
+  operator()(_Range&& __r, _Pred __pred, _Proj __proj = {}) const
   {
-  return ranges::any_of(ranges::begin(__r), ranges::end(__r),
+   return (*this)(ranges::begin(__r), ranges::end(__r),
  std::move(__pred), std::move(__proj));
   }
+  };
 
+  inline constexpr __any_of_fn any_of{};
+
+  struct __none_of_fn
+  {
 template _Sent,
 typename _Proj = identity,
 indirect_unary_predicate> _Pred>
   constexpr bool
-none_of(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {})
+  operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) 
const
   {
for (; __first != __last; ++__first)
  if (std::__invoke(__pred, std::__invoke(__proj, *__first)))
@@ -124,11 +136,14 @@ namespace ranges
 template, _Proj>> 
_Pred>
   constexpr bool
-n

Re: [PATCH 1/3] libstdc++: Fold some ranges algo subroutines into their only caller

2020-02-15 Thread Patrick Palka
On Sat, 15 Feb 2020, Jonathan Wakely wrote:

> On 14/02/20 10:35 -0500, Patrick Palka wrote:
> > These subroutines have only a single call site, so it might be best and
> > simplest
> > to eliminate them before we convert the algos into function objects.
> > 
> > libstdc++-v3/ChangeLog:
> > 
> > * include/bits/ranges_algo.h (ranges::__find_end): Fold into ...
> > (ranges::find_end): ... here.
> > (ranges::__lexicographical_compare): Fold into ...
> > (ranges::lexicographical_compare): ... here.
> > * include/bits/ranges_algobase.h (ranges::__equal): Fold into ...
> > (ranges::equal): ... here.
> 
> OK for master, but please note the two comments below.
> 
> 
> > libstdc++-v3/include/bits/ranges_algo.h | 104 
> > libstdc++-v3/include/bits/ranges_algobase.h |  33 +++
> > 2 files changed, 55 insertions(+), 82 deletions(-)
> > 
> > diff --git a/libstdc++-v3/include/bits/ranges_algo.h
> > b/libstdc++-v3/include/bits/ranges_algo.h
> > index 84a02cabb80..6b6f4defdf5 100644
> > --- a/libstdc++-v3/include/bits/ranges_algo.h
> > +++ b/libstdc++-v3/include/bits/ranges_algo.h
> > @@ -513,40 +513,7 @@ namespace ranges
> >   std::move(__pred), std::move(__proj));
> > }
> > 
> > -  template _Sent1,
> > -  forward_iterator _Iter2, sentinel_for<_Iter2> _Sent2,
> > -  typename _Pred = ranges::equal_to,
> > -  typename _Proj1 = identity, typename _Proj2 = identity>
> > -requires indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2>
> > -constexpr subrange<_Iter1>
> > -__find_end(_Iter1 __first1, _Sent1 __last1,
> > -  _Iter2 __first2, _Sent2 __last2,
> > -  _Pred __pred, _Proj1 __proj1, _Proj2 __proj2)
> > -{
> > -  auto __i = ranges::next(__first1, __last1);
> > -  if (__first2 == __last2)
> > -   return {__i, __i};
> > 
> > -  auto __result_begin = __i;
> > -  auto __result_end = __i;
> > -  for (;;)
> > -   {
> > - auto __new_range = ranges::search(__first1, __last1,
> > -   __first2, __last2,
> > -   __pred, __proj1, __proj2);
> > - auto __new_result_begin = ranges::begin(__new_range);
> > - auto __new_result_end = ranges::end(__new_range);
> > - if (__new_result_begin == __last1)
> > -   return {__result_begin, __result_end};
> > - else
> > -   {
> > - __result_begin = __new_result_begin;
> > - __result_end = __new_result_end;
> > - __first1 = __result_begin;
> > - ++__first1;
> > -   }
> > -   }
> > -}
> > 
> >   template _Sent1,
> >forward_iterator _Iter2, sentinel_for<_Iter2> _Sent2,
> > @@ -578,9 +545,31 @@ namespace ranges
> > return {__result_first, __result_last};
> > }
> >   else
> > -   return ranges::__find_end(__first1, __last1, __first2, __last2,
> > - std::move(__pred),
> > - std::move(__proj1), std::move(__proj2));
> > +   {
> > + auto __i = ranges::next(__first1, __last1);
> > + if (__first2 == __last2)
> > +   return {__i, __i};
> > +
> > + auto __result_begin = __i;
> > + auto __result_end = __i;
> > + for (;;)
> > +   {
> > + auto __new_range = ranges::search(__first1, __last1,
> > +   __first2, __last2,
> > +   __pred, __proj1, __proj2);
> > + auto __new_result_begin = ranges::begin(__new_range);
> > + auto __new_result_end = ranges::end(__new_range);
> > + if (__new_result_begin == __last1)
> > +   return {__result_begin, __result_end};
> > + else
> > +   {
> > + __result_begin = __new_result_begin;
> > + __result_end = __new_result_end;
> > + __first1 = __result_begin;
> > + ++__first1;
> > +   }
> > +   }
> > +   }
> > }
> > 
> >   template > @@ -2908,14 +2897,26 @@ namespace ranges
> > 
> >   template _Sent1,
> >input_iterator _Iter2, sentinel_for<_Iter2> _Sent2,
> > -  typename _Proj1, typename _Proj2,
> > +  typename _Proj1 = identity, typename _Proj2 = identity,
> >indirect_strict_weak_order,
> > - 

[PATCH] libstdc++: Move code after an early exit constexpr if to under an else branch

2020-02-15 Thread Patrick Palka
This avoids instantiating dead code when the true branch of the constexpr if is
taken.

[ diffstat generated with -w to ignore noisy whitespace changes ]

libstdc++-v3/ChangeLog:

* include/bits/ranges_algo.h (__lexicographical_compare_fn::operator()):
Move code after an early exit constexpr if to under an else branch.
* include/bits/ranges_algobase.h (__equal_fn::operator()): Likewise.
---
 libstdc++-v3/include/bits/ranges_algo.h | 7 +--
 libstdc++-v3/include/bits/ranges_algobase.h | 7 ++-
 3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/libstdc++-v3/include/bits/ranges_algo.h 
b/libstdc++-v3/include/bits/ranges_algo.h
index 7f8f0fb964b..ff1b40f6ace 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -3318,7 +3318,8 @@ namespace ranges
 std::__niter_base(std::move(__last2)),
 std::move(__comp),
 std::move(__proj1), std::move(__proj2));
-
+   else
+ {
constexpr bool __sized_iters
  = (sized_sentinel_for<_Sent1, _Iter1>
 && sized_sentinel_for<_Sent2, _Iter2>);
@@ -3342,7 +3343,8 @@ namespace ranges
  {
if (const auto __len = std::min(__d1, __d2))
  {
-   const auto __c = std::__memcmp(__first1, __first2, __len);
+   const auto __c
+ = std::__memcmp(__first1, __first2, __len);
if constexpr (is_same_v<_Comp, ranges::less>)
  {
if (__c < 0)
@@ -3378,6 +3380,7 @@ namespace ranges
  }
return __first1 == __last1 && __first2 != __last2;
  }
+  }
 
 template
-&& sized_sentinel_for<_Sent2, _Iter2>);
-   if constexpr (__sized_iters)
+   else if constexpr (sized_sentinel_for<_Sent1, _Iter1>
+  && sized_sentinel_for<_Sent2, _Iter2>)
  {
auto __d1 = ranges::distance(__first1, __last1);
auto __d2 = ranges::distance(__first2, __last2);
-- 
2.25.0.232.gd8437c57fa



Re: [PATCH] c++/modules: depending local enums [PR104919, PR106009]

2024-03-01 Thread Patrick Palka
On Fri, 1 Mar 2024, Jason Merrill wrote:

> On 2/29/24 15:56, Patrick Palka wrote:
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> > OK for trunk?
> > 
> > -- >8 --
> > 
> > For local enums defined in a non-template function or a function template
> > instantiation it seems we neglect to make the function depend on the enum
> > definition, which ultimately causes streaming to fail due to the enum
> > definition not being streamed before uses of its enumerators are streamed,
> > as far as I can tell.
> 
> I would think that the function doesn't need to depend on the local enum in
> order for the local enum to be streamed before the use of the enumerator,
> which comes after the definition of the enum in the function body?
> 
> Why isn't streaming the body of the function outputting the enum definition
> before the use of the enumerator?

IIUC (based on observing the behavior for local classes) streaming the
definition of a local class/enum as part of the function definition is
what we want to avoid; we want to treat a local type definition as a
logically separate definition and stream it separately (similar
to class defns vs member defns I guess).  And by not registering a dependency
between the function and the local enum, we end up never streaming out
the local enum definition separately and instead stream it out as part
of the function definition (accidentally) which we then can't stream in
properly.

Perhaps the motivation for treating local type definitions as logically
separate from the function definition is because they can leak out of a
function with a deduced return type:

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

  using type = decltype(f()); // refers directly to f()::A

It's also consistent with templated local types getting their own
TEMPLATE_DECL (which Nathan revisited in r11-4529-g9703b8d98c116e).

> 
> > This was nearly enough to make things work, except we now ran into
> > issues with the local TYPE/CONST_DECL copies when streaming the
> > constexpr version of a function body.  It occurred to me that we don't
> > need to make copies of local types when copying a constexpr function
> > body; only VAR_DECLs etc need to be copied for sake of recursive
> > constexpr calls.  So this patch adjusts copy_fn accordingly.
> 
> Maybe adjust can_be_nonlocal instead?  It seems unnecessary in general to
> remap types and enumerators for inlining.

That seems to work nicely too.  I'm testing a patch to that effect with
all front ends and will report back.

> 
> Jason
> 
> 



Re: [PATCH] c++: auto(x) partial substitution [PR110025, PR114138]

2024-03-01 Thread Patrick Palka
On Fri, 1 Mar 2024, Jason Merrill wrote:

> On 2/29/24 14:17, Patrick Palka wrote:
> > On Wed, 28 Feb 2024, Jason Merrill wrote:
> > > I wonder about, rather than returning it directly, setting its level to 1
> > > for
> > > the substitution?
> > 
> > Done, that works nicely.
> > 
> > > Then I wonder if it would be feasible to give all autos level 0 and adjust
> > > it
> > > here?  That's probably not a stage 4 change, though...
> > 
> > It seems feasible.  I experimented doing this in the past[1] and ran
> > into two complications.  One complication was with constrained auto
> > deduction, e.g.
> > 
> >template
> >void g() {
> >  C auto x = ...;
> >};
> > 
> > Here the underlying concept-id that we enter satisfaction with is
> > C where this auto has level one greater than the template
> > depth, and the argument vector we pass has an extra innermost level
> > containing the deduced type, so things match up nicely.  This seems
> > to be the only place where we truly need auto to have a non 0/1 level.
> > In my WIP patch in that thread I just made do_auto_deduction build the
> > concept-id C in terms of an auto of the proper level before
> > entering satisfaction, which was kind of ugly but worked.
> 
> So maybe set its level to TMPL_ARGS_DEPTH (targs) after add_to_template_args,
> rather than 1?

AFAICT in-place type modification in this case would be unsafe or at
least difficult to reason about due to the satisfaction/normalization
caches.  We would cache the result as if the auto had the nonzero level
and then (presumably) reset its level back to 0 afterward, leaving the
hash tables in an inconsistent state.

> 
> > The other complication was with Concepts TS extended auto deduction:
> > 
> >tuple t = tuple{};
> > 
> > because unify_pack_expansion (called from fn_type_unification during
> > do_auto_deduction) isn't prepared to see a parameter pack of level 0
> > (unify has no problems with ordinary tparms of level 0 though).  This
> > shouldn't be too hard to fix though.
> > 
> > How does the following look for trunk and perhaps 13 (there should be
> > no functional change for code that doesn't use auto(x))?
> > 
> > [1]: https://gcc.gnu.org/pipermail/gcc-patches/2022-January/587818.html
> > 
> > -- >8 --
> > 
> > PR c++/110025
> > PR c++/114138
> > 
> > gcc/cp/ChangeLog:
> > 
> > * cp-tree.h (make_cast_auto): Declare.
> > * parser.cc (cp_parser_functional_cast): Replace a parsed auto
> > with a level-less one via make_cast_auto.
> > * pt.cc (find_parameter_packs_r): Don't treat level-less auto
> > as a type parameter pack.
> > (tsubst) : Generalized CTAD placeholder
> > handling to all level-less autos.
> > (make_cast_auto): Define.
> > (do_auto_deduction): Handle replacement of a level-less auto.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/cpp23/auto-fncast16.C: New test.
> > * g++.dg/cpp23/auto-fncast17.C: New test.
> > * g++.dg/cpp23/auto-fncast18.C: New test.
> > ---
> >   gcc/cp/cp-tree.h   |  1 +
> >   gcc/cp/parser.cc   | 11 
> >   gcc/cp/pt.cc   | 37 +++-
> >   gcc/testsuite/g++.dg/cpp23/auto-fncast16.C | 12 
> >   gcc/testsuite/g++.dg/cpp23/auto-fncast17.C | 15 +
> >   gcc/testsuite/g++.dg/cpp23/auto-fncast18.C | 69 ++
> >   6 files changed, 142 insertions(+), 3 deletions(-)
> >   create mode 100644 gcc/testsuite/g++.dg/cpp23/auto-fncast16.C
> >   create mode 100644 gcc/testsuite/g++.dg/cpp23/auto-fncast17.C
> >   create mode 100644 gcc/testsuite/g++.dg/cpp23/auto-fncast18.C
> > 
> > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> > index 04c3aa6cd91..6f1da1c7bad 100644
> > --- a/gcc/cp/cp-tree.h
> > +++ b/gcc/cp/cp-tree.h
> > @@ -7476,6 +7476,7 @@ extern tree make_decltype_auto
> > (void);
> >   extern tree make_constrained_auto (tree, tree);
> >   extern tree make_constrained_decltype_auto(tree, tree);
> >   extern tree make_template_placeholder (tree);
> > +extern tree make_cast_auto (void);
> >   extern bool template_placeholder_p(tree);
> >   extern bool ctad_template_p   (tree);
> >   extern bool unparenthesized_id_or_class_member_access_p (tree);
> > diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> > inde

Re: [PATCH] c++/modules: depending local enums [PR104919, PR106009]

2024-03-01 Thread Patrick Palka
On Fri, 1 Mar 2024, Jason Merrill wrote:

> On 3/1/24 10:00, Patrick Palka wrote:
> > On Fri, 1 Mar 2024, Jason Merrill wrote:
> > 
> > > On 2/29/24 15:56, Patrick Palka wrote:
> > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> > > > OK for trunk?
> > > > 
> > > > -- >8 --
> > > > 
> > > > For local enums defined in a non-template function or a function
> > > > template
> > > > instantiation it seems we neglect to make the function depend on the
> > > > enum
> > > > definition, which ultimately causes streaming to fail due to the enum
> > > > definition not being streamed before uses of its enumerators are
> > > > streamed,
> > > > as far as I can tell.
> > > 
> > > I would think that the function doesn't need to depend on the local enum
> > > in
> > > order for the local enum to be streamed before the use of the enumerator,
> > > which comes after the definition of the enum in the function body?
> > > 
> > > Why isn't streaming the body of the function outputting the enum
> > > definition
> > > before the use of the enumerator?
> > 
> > IIUC (based on observing the behavior for local classes) streaming the
> > definition of a local class/enum as part of the function definition is
> > what we want to avoid; we want to treat a local type definition as a
> > logically separate definition and stream it separately (similar
> > to class defns vs member defns I guess).  And by not registering a
> > dependency
> > between the function and the local enum, we end up never streaming out
> > the local enum definition separately and instead stream it out as part
> > of the function definition (accidentally) which we then can't stream in
> > properly.
> > 
> > Perhaps the motivation for treating local type definitions as logically
> > separate from the function definition is because they can leak out of a
> > function with a deduced return type:
> > 
> >auto f() {
> >  struct A { };
> >  return A();
> >}
> > 
> >using type = decltype(f()); // refers directly to f()::A
> 
> Yes, I believe that's what modules.cc refers to as a "voldemort".
> 
> But for non-voldemort local types, the declaration of the function doesn't
> depend on them, only the definition.  Why doesn't streaming them in the
> definition work properly?

I should note that for a templated local type we already always add a
dependency between the function template _pattern_ and the local type
_pattern_ and therefore always stream the local type pattern separately
(even if its not actually a voldemort), thanks to the TREE_CODE (decl) == 
TEMPLATE_DECL
case guarding the add_dependency call (inside a template pattern we
see the TEMPLATE_DECL of the local TYPE_DECL).  The dependency is
missing only when the function is a non-template or non-template-pattern.
My patch makes us consistently add the dependency and in turn consistently 
stream the definitions separately.

(For a local _class_, in the non-template and non-template-pattern case
we currently add a dependency between the function and the
injected-class-name of the class as opposed to the class itself, which
seems quite accidental but suffices.  And that's why only local enums
are problematic currently.  After my patch we instead add a dependency
to the local class itself.)

Part of the puzzle of why we don't/can't stream them as part of the
function definition is because we don't mark the enumerators for
by-value walking when marking the function definition.  So when
streaming out the enumerator definition we stream out _references_
to the enumerators (tt_const_decl tags) instead of the actual
definitions which breaks stream-in.

The best place to mark local types for by-value walking would be
in trees_out::mark_function_def which is suspiciously empty!  I
experimented with (never mind that it only marks the outermost block's
types):

@@ -11713,8 +11713,12 @@ trees_out::write_function_def (tree decl)
 }
 
 void
-trees_out::mark_function_def (tree)
+trees_out::mark_function_def (tree decl)
 {
+  tree initial = DECL_INITIAL (decl);
+  for (tree var = BLOCK_VARS (initial); var; var = DECL_CHAIN (var))
+if (DECL_IMPLICIT_TYPEDEF_P (var))
+  mark_declaration (var, true);
 }

Which actually fixes the non-template PR104919 testcase, but it
breaks streaming of templated local types wherein we run into
the sanity check:

@@ -7677,16 +7677,6 @@ trees_out::decl_value (tree decl, depset *dep)
 
   merge_kind mk = get_merge_kind (decl, dep);
 
!  if (CHECKING_P)
!{
!  /* Never st

Re: [PATCH] c++/modules: depending local enums [PR104919, PR106009]

2024-03-01 Thread Patrick Palka
On Fri, 1 Mar 2024, Jason Merrill wrote:

> On 3/1/24 10:32, Jason Merrill wrote:
> > On 3/1/24 10:00, Patrick Palka wrote:
> > > On Fri, 1 Mar 2024, Jason Merrill wrote:
> > > 
> > > > On 2/29/24 15:56, Patrick Palka wrote:
> > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> > > > > OK for trunk?
> > > > > 
> > > > > -- >8 --
> > > > > 
> > > > > For local enums defined in a non-template function or a function
> > > > > template
> > > > > instantiation it seems we neglect to make the function depend on the
> > > > > enum
> > > > > definition, which ultimately causes streaming to fail due to the enum
> > > > > definition not being streamed before uses of its enumerators are
> > > > > streamed,
> > > > > as far as I can tell.
> > > > 
> > > > I would think that the function doesn't need to depend on the local enum
> > > > in
> > > > order for the local enum to be streamed before the use of the
> > > > enumerator,
> > > > which comes after the definition of the enum in the function body?
> > > > 
> > > > Why isn't streaming the body of the function outputting the enum
> > > > definition
> > > > before the use of the enumerator?
> > > 
> > > IIUC (based on observing the behavior for local classes) streaming the
> > > definition of a local class/enum as part of the function definition is
> > > what we want to avoid; we want to treat a local type definition as a
> > > logically separate definition and stream it separately (similar
> > > to class defns vs member defns I guess).  And by not registering a
> > > dependency
> > > between the function and the local enum, we end up never streaming out
> > > the local enum definition separately and instead stream it out as part
> > > of the function definition (accidentally) which we then can't stream in
> > > properly.
> > > 
> > > Perhaps the motivation for treating local type definitions as logically
> > > separate from the function definition is because they can leak out of a
> > > function with a deduced return type:
> > > 
> > >    auto f() {
> > >  struct A { };
> > >  return A();
> > >    }
> > > 
> > >    using type = decltype(f()); // refers directly to f()::A
> > 
> > Yes, I believe that's what modules.cc refers to as a "voldemort".
> > 
> > But for non-voldemort local types, the declaration of the function doesn't
> > depend on them, only the definition.  Why doesn't streaming them in the
> > definition work properly?
> 
> And does your 99426 patch address that problem?

I don't think so, that patch should only affect declaration merging (of
a streamed-in local type with the corresponding in-TU local type after
their containing function is merged).


> > This was nearly enough to make things work, except we now ran into
> > issues with the local TYPE/CONST_DECL copies when streaming the
> > constexpr version of a function body.  It occurred to me that we don't
> > need to make copies of local types when copying a constexpr function
> > body; only VAR_DECLs etc need to be copied for sake of recursive
> > constexpr calls.  So this patch adjusts copy_fn accordingly.
>
> Maybe adjust can_be_nonlocal instead?  It seems unnecessary in general
> to remap types and enumerators for inlining.

Unfortunately this approached caused a boostrap failure with Ada:

raised STORAGE_ERROR : stack overflow or erroneous memory access

The patch was

--- a/gcc/tree-inline.cc
+++ b/gcc/tree-inline.cc
@@ -725,6 +725,9 @@ can_be_nonlocal (tree decl, copy_body_data *id)
   if (TREE_CODE (decl) == FUNCTION_DECL)
 return true;
 
+  if (TREE_CODE (decl) == TYPE_DECL || TREE_CODE (decl) == CONST_DECL)
+return true;
+
   /* Local static vars must be non-local or we get multiple declaration
  problems.  */
   if (VAR_P (decl) && !auto_var_in_fn_p (decl, id->src_fn))


> 
> Jason
> 
> 

Re: [PATCH] c++/modules: depending local enums [PR104919, PR106009]

2024-03-01 Thread Patrick Palka
On Fri, 1 Mar 2024, Patrick Palka wrote:

> On Fri, 1 Mar 2024, Jason Merrill wrote:
> 
> > On 3/1/24 10:00, Patrick Palka wrote:
> > > On Fri, 1 Mar 2024, Jason Merrill wrote:
> > > 
> > > > On 2/29/24 15:56, Patrick Palka wrote:
> > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> > > > > OK for trunk?
> > > > > 
> > > > > -- >8 --
> > > > > 
> > > > > For local enums defined in a non-template function or a function
> > > > > template
> > > > > instantiation it seems we neglect to make the function depend on the
> > > > > enum
> > > > > definition, which ultimately causes streaming to fail due to the enum
> > > > > definition not being streamed before uses of its enumerators are
> > > > > streamed,
> > > > > as far as I can tell.
> > > > 
> > > > I would think that the function doesn't need to depend on the local enum
> > > > in
> > > > order for the local enum to be streamed before the use of the 
> > > > enumerator,
> > > > which comes after the definition of the enum in the function body?
> > > > 
> > > > Why isn't streaming the body of the function outputting the enum
> > > > definition
> > > > before the use of the enumerator?
> > > 
> > > IIUC (based on observing the behavior for local classes) streaming the
> > > definition of a local class/enum as part of the function definition is
> > > what we want to avoid; we want to treat a local type definition as a
> > > logically separate definition and stream it separately (similar
> > > to class defns vs member defns I guess).  And by not registering a
> > > dependency
> > > between the function and the local enum, we end up never streaming out
> > > the local enum definition separately and instead stream it out as part
> > > of the function definition (accidentally) which we then can't stream in
> > > properly.
> > > 
> > > Perhaps the motivation for treating local type definitions as logically
> > > separate from the function definition is because they can leak out of a
> > > function with a deduced return type:
> > > 
> > >auto f() {
> > >  struct A { };
> > >  return A();
> > >}
> > > 
> > >using type = decltype(f()); // refers directly to f()::A
> > 
> > Yes, I believe that's what modules.cc refers to as a "voldemort".
> > 
> > But for non-voldemort local types, the declaration of the function doesn't
> > depend on them, only the definition.  Why doesn't streaming them in the
> > definition work properly?
> 
> I should note that for a templated local type we already always add a
> dependency between the function template _pattern_ and the local type
> _pattern_ and therefore always stream the local type pattern separately
> (even if its not actually a voldemort), thanks to the TREE_CODE (decl) == 
> TEMPLATE_DECL
> case guarding the add_dependency call (inside a template pattern we
> see the TEMPLATE_DECL of the local TYPE_DECL).  The dependency is
> missing only when the function is a non-template or non-template-pattern.
> My patch makes us consistently add the dependency and in turn consistently 
> stream the definitions separately.
> 
> (For a local _class_, in the non-template and non-template-pattern case
> we currently add a dependency between the function and the
> injected-class-name of the class as opposed to the class itself, which
> seems quite accidental but suffices.  And that's why only local enums
> are problematic currently.  After my patch we instead add a dependency
> to the local class itself.)
> 
> Part of the puzzle of why we don't/can't stream them as part of the
> function definition is because we don't mark the enumerators for
> by-value walking when marking the function definition.  So when
> streaming out the enumerator definition we stream out _references_
> to the enumerators (tt_const_decl tags) instead of the actual
> definitions which breaks stream-in.
> 
> The best place to mark local types for by-value walking would be
> in trees_out::mark_function_def which is suspiciously empty!  I
> experimented with (never mind that it only marks the outermost block's
> types):
> 
> @@ -11713,8 +11713,12 @@ trees_out::write_function_def (tree decl)
>  }
>  
>  void
> -trees_out::mark_function_def (tree)
> +tr

  1   2   3   4   5   6   7   8   9   10   >