Re: [PATCH] c++: constexpr init of union sub-aggr w/ base [PR105491]

2022-05-06 Thread Patrick Palka via Gcc-patches
On Fri, 6 May 2022, Patrick Palka wrote:

> On Fri, 6 May 2022, Jason Merrill wrote:
> 
> > On 5/6/22 11:22, Patrick Palka wrote:
> > > Here ever since r10-7313-gb599bf9d6d1e18, reduced_constant_expression_p
> > > in C++11/14 is rejecting the marked sub-aggregate initializer (of type S)
> > > 
> > >W w = {.D.2445={.s={.D.2387={.m=0}, .b=0}}}
> > >   ^
> > > 
> > > ultimately because said initializer has CONSTRUCTOR_NO_CLEARING set, and
> > > so the function proceeds to verify that all fields of S are initialized.
> > > And before C++17 we don't expect to see base class fields (since
> > > next_initializable_field skips over the), so the base class initializer
> > > causes r_c_e_p to return false.
> > 
> > That seems like the primary bug.  I guess r_c_e_p shouldn't be using
> > next_initializable_field.  Really that function should only be used for
> > aggregates.
> 
> I see, I'll try replacing it in r_c_e_p.  Would that be in addition to
> or instead of the clear_no_implicit_zero approach?

I'm testing the following, which uses a custom predicate instead of
next_initializable_field in r_c_e_p.

-- >8 --

gcc/cp/ChangeLog:

* constexpr.cc (reduced_constant_expression_p): Replace use of
next_initializable_field with custom predicate.  Refactor to
remove the use of goto.
* decl.cc (next_initializable_field): Skip over vptr fields.
Document that this function is to be used only for aggregate
classes.
---
 gcc/cp/constexpr.cc | 65 ++---
 gcc/cp/decl.cc  | 15 +--
 2 files changed, 44 insertions(+), 36 deletions(-)

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 9b1e71857fc..d1cd556591c 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -3016,7 +3016,6 @@ reduced_constant_expression_p (tree t)
 
 case CONSTRUCTOR:
   /* And we need to handle PTRMEM_CST wrapped in a CONSTRUCTOR.  */
-  tree field;
   if (CONSTRUCTOR_NO_CLEARING (t))
{
  if (TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
@@ -3041,42 +3040,54 @@ reduced_constant_expression_p (tree t)
}
  if (find_array_ctor_elt (t, max) == -1)
return false;
- goto ok;
}
- else if (cxx_dialect >= cxx20
-  && TREE_CODE (TREE_TYPE (t)) == UNION_TYPE)
+ else if (TREE_CODE (TREE_TYPE (t)) == UNION_TYPE)
{
- if (CONSTRUCTOR_NELTS (t) == 0)
+ if (CONSTRUCTOR_NELTS (t) != 1)
/* An initialized union has a constructor element.  */
return false;
- /* And it only initializes one member.  */
- field = NULL_TREE;
+ if (!reduced_constant_expression_p (CONSTRUCTOR_ELT (t, 
0)->value))
+   return false;
}
  else
-   field = next_initializable_field (TYPE_FIELDS (TREE_TYPE (t)));
+   {
+ /* Similar to the predicate used in next_initializable_field,
+except that we additionally skip over empty types (for which
+we don't require an initializer), and we always consider base
+class fields (not just in C++17 mode) and vptr fields.  */
+ auto ignorable_field_p = [] (tree field) {
+   if (!field)
+ return false;
+   return (TREE_CODE (field) != FIELD_DECL
+   || DECL_UNNAMED_BIT_FIELD (field)
+   || (DECL_ARTIFICIAL (field)
+   && !DECL_FIELD_IS_BASE (field)
+   && !DECL_VIRTUAL_P (field))
+   || is_really_empty_class (TREE_TYPE (field),
+ /*ignore_vptr*/false));
+ };
+ tree field = TYPE_FIELDS (TREE_TYPE (t));
+ for (auto : CONSTRUCTOR_ELTS (t))
+   {
+ if (!reduced_constant_expression_p (e.value))
+   return false;
+ while (e.index != field && ignorable_field_p (field))
+   field = DECL_CHAIN (field);
+ if (e.index == field)
+   field = DECL_CHAIN (field);
+ else
+   return false;
+   }
+ while (ignorable_field_p (field))
+   field = DECL_CHAIN (field);
+ if (field)
+   return false;
+   }
}
   else
-   field = NULL_TREE;
-  for (auto : CONSTRUCTOR_ELTS (t))
-   {
- /* If VAL is null, we're in the middle of initializing this
-element.  */
+   for (auto : CONSTRUCTOR_ELTS (t))
  if (!reduced_constant_expression_p (e.value))
   

Re: [PATCH] c++: constexpr init of union sub-aggr w/ base [PR105491]

2022-05-06 Thread Patrick Palka via Gcc-patches
On Fri, 6 May 2022, Jason Merrill wrote:

> On 5/6/22 11:22, Patrick Palka wrote:
> > Here ever since r10-7313-gb599bf9d6d1e18, reduced_constant_expression_p
> > in C++11/14 is rejecting the marked sub-aggregate initializer (of type S)
> > 
> >W w = {.D.2445={.s={.D.2387={.m=0}, .b=0}}}
> >   ^
> > 
> > ultimately because said initializer has CONSTRUCTOR_NO_CLEARING set, and
> > so the function proceeds to verify that all fields of S are initialized.
> > And before C++17 we don't expect to see base class fields (since
> > next_initializable_field skips over the), so the base class initializer
> > causes r_c_e_p to return false.
> 
> That seems like the primary bug.  I guess r_c_e_p shouldn't be using
> next_initializable_field.  Really that function should only be used for
> aggregates.

I see, I'll try replacing it in r_c_e_p.  Would that be in addition to
or instead of the clear_no_implicit_zero approach?

> 
> > The base class initializer comes from
> > the constructor call S::S(int).
> > 
> > The reason this is caused by r10-7313-gb599bf9d6d1e18 is because in that
> > commit we began using CONSTRUCTOR_NO_CLEARING to also track whether we're
> > in middle of activating a union member.  This overloaded use of the flag
> > affects clear_no_implicit_zero, which recurses into sub-aggregate
> > initializers only if the outer initializer has CONSTRUCTOR_NO_CLEARING
> > set.
> 
> Is that really overloaded?  In both union and non-union cases, it indicates
> that the object is not completely initialized.

Ah yes, makes sense.  More accurately the immediate clearing of
CONSTRUCTOR_NO_CLEARING after activating a union member at the end of
cxx_eval_store_expression is what affects clear_no_implicit_zero later.

> 
> > After that commit, the outer union initializer above no longer has
> > the flag set at this point and so clear_no_implicit_zero no longer clears
> > CONSTRUCTOR_NO_CLEARING for the marked inner initializer.
> 
> Why wasn't it cleared for the inner initializer as part of that evaluation?

Looks like the inner initializer {.D.2387={.m=0}, .b=0} is formed during
the subobject constructor call:

  V::V (&((struct S *) this)->D.2120);

after the evaluation of which, 'result' in cxx_eval_call_expression is NULL
(presumably because it's a CALL_EXPR, not AGGR_INIT_EXPR?):

  /* This can be null for a subobject constructor call, in
 which case what we care about is the initialization
 side-effects rather than the value.  We could get at the
 value by evaluating *this, but we don't bother; there's
 no need to put such a call in the hash table.  */
  result = lval ? ctx->object : ctx->ctor;

so we end up not calling clear_no_implicit_zero for the inner initializer
directly.  We only call clear_no_implicit_zero after evaluating the
AGGR_INIT_EXPR for outermost initializer (of type W).

> 
> > This patch fixes this by restoring the recursive behavior of
> > clear_no_implicit_zero for union initializers.  Arguably we should
> > we could improve reduced_constant_expression_p to accept the marked
> > initializer in C++11/14 even if it has CONSTRUCTOR_NO_CLEARING set, but
> > adjusting clear_no_implicit_zero seems safer to backport.
> > 
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > trunk/12/11/10?
> > 
> > PR c++/105491
> > 
> > gcc/cp/ChangeLog:
> > 
> > * constexpr.cc (clear_no_implicit_zero): Recurse into a union
> > initializer even if CONSTRUCTOR_NO_CLEARING is already cleared.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/cpp0x/constexpr-union7.C: New test.
> > * g++.dg/cpp0x/constexpr-union7a.C: New test.
> > * g++.dg/cpp2a/constinit17.C: New test.
> > ---
> >   gcc/cp/constexpr.cc   |  7 +-
> >   gcc/testsuite/g++.dg/cpp0x/constexpr-union7.C | 17 +
> >   .../g++.dg/cpp0x/constexpr-union7a.C  | 15 
> >   gcc/testsuite/g++.dg/cpp2a/constinit17.C  | 24 +++
> >   4 files changed, 62 insertions(+), 1 deletion(-)
> >   create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-union7.C
> >   create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-union7a.C
> >   create mode 100644 gcc/testsuite/g++.dg/cpp2a/constinit17.C
> > 
> > diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> > index 9b1e71857fc..75fecbcbcb7 100644
> > --- a/gcc/cp/constexpr.cc
> > +++ b/gcc/cp/constexpr.cc
> > @@ -1886,7 +1886,12 @@ cxx_eval_internal_function (const constexpr_ctx *ctx,
> > tree t,
> >   static void
> >   clear_no_implicit_

[PATCH] c++: constexpr init of union sub-aggr w/ base [PR105491]

2022-05-06 Thread Patrick Palka via Gcc-patches
Here ever since r10-7313-gb599bf9d6d1e18, reduced_constant_expression_p
in C++11/14 is rejecting the marked sub-aggregate initializer (of type S)

  W w = {.D.2445={.s={.D.2387={.m=0}, .b=0}}}
 ^

ultimately because said initializer has CONSTRUCTOR_NO_CLEARING set, and
so the function proceeds to verify that all fields of S are initialized.
And before C++17 we don't expect to see base class fields (since
next_initializable_field skips over the), so the base class initializer
causes r_c_e_p to return false.  The base class initializer comes from
the constructor call S::S(int).

The reason this is caused by r10-7313-gb599bf9d6d1e18 is because in that
commit we began using CONSTRUCTOR_NO_CLEARING to also track whether we're
in middle of activating a union member.  This overloaded use of the flag
affects clear_no_implicit_zero, which recurses into sub-aggregate
initializers only if the outer initializer has CONSTRUCTOR_NO_CLEARING
set.  After that commit, the outer union initializer above no longer has
the flag set at this point and so clear_no_implicit_zero no longer clears
CONSTRUCTOR_NO_CLEARING for the marked inner initializer.

This patch fixes this by restoring the recursive behavior of
clear_no_implicit_zero for union initializers.  Arguably we should
we could improve reduced_constant_expression_p to accept the marked
initializer in C++11/14 even if it has CONSTRUCTOR_NO_CLEARING set, but
adjusting clear_no_implicit_zero seems safer to backport.

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

PR c++/105491

gcc/cp/ChangeLog:

* constexpr.cc (clear_no_implicit_zero): Recurse into a union
initializer even if CONSTRUCTOR_NO_CLEARING is already cleared.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/constexpr-union7.C: New test.
* g++.dg/cpp0x/constexpr-union7a.C: New test.
* g++.dg/cpp2a/constinit17.C: New test.
---
 gcc/cp/constexpr.cc   |  7 +-
 gcc/testsuite/g++.dg/cpp0x/constexpr-union7.C | 17 +
 .../g++.dg/cpp0x/constexpr-union7a.C  | 15 
 gcc/testsuite/g++.dg/cpp2a/constinit17.C  | 24 +++
 4 files changed, 62 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-union7.C
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-union7a.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/constinit17.C

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 9b1e71857fc..75fecbcbcb7 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -1886,7 +1886,12 @@ cxx_eval_internal_function (const constexpr_ctx *ctx, 
tree t,
 static void
 clear_no_implicit_zero (tree ctor)
 {
-  if (CONSTRUCTOR_NO_CLEARING (ctor))
+  if (CONSTRUCTOR_NO_CLEARING (ctor)
+  /* For a union initializer, the flag could already be cleared but not
+necessarily yet for its sub-aggregates, since for unions the flag is
+also used by cxx_eval_store_expression to track whether we're in the
+middle of activating one of its members.  */
+  || TREE_CODE (TREE_TYPE (ctor)) == UNION_TYPE)
 {
   CONSTRUCTOR_NO_CLEARING (ctor) = false;
   for (auto : CONSTRUCTOR_ELTS (ctor))
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-union7.C 
b/gcc/testsuite/g++.dg/cpp0x/constexpr-union7.C
new file mode 100644
index 000..b3147d9db50
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-union7.C
@@ -0,0 +1,17 @@
+// PR c++/105491
+// { dg-do compile { target c++11 } }
+
+struct V {
+  int m = 0;
+};
+struct S : V {
+  constexpr S(int) : b() { }
+  bool b;
+};
+struct W {
+  constexpr W() : s(0) { }
+  union {
+S s;
+  };
+};
+constexpr W w;
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-union7a.C 
b/gcc/testsuite/g++.dg/cpp0x/constexpr-union7a.C
new file mode 100644
index 000..b676e7d1748
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-union7a.C
@@ -0,0 +1,15 @@
+// PR c++/105491
+// { dg-do compile { target c++11 } }
+
+struct V {
+  int m = 0;
+};
+struct S : V {
+  constexpr S(int) : b() { }
+  bool b;
+};
+union W {
+  constexpr W() : s(0) { }
+  S s;
+};
+constexpr W w;
diff --git a/gcc/testsuite/g++.dg/cpp2a/constinit17.C 
b/gcc/testsuite/g++.dg/cpp2a/constinit17.C
new file mode 100644
index 000..6431654ac85
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/constinit17.C
@@ -0,0 +1,24 @@
+// PR c++/105491
+// { dg-do compile { target c++11 } }
+
+class Message {
+  virtual int GetMetadata();
+};
+class ProtobufCFileOptions : Message {
+public:
+  constexpr ProtobufCFileOptions(int);
+  bool no_generate_;
+  bool const_strings_;
+  bool use_oneof_field_name_;
+  bool gen_pack_helpers_;
+  bool gen_init_helpers_;
+};
+constexpr ProtobufCFileOptions::ProtobufCFileOptions(int)
+: no_generate_(), const_strings_(), use_oneof_field_name_(),
+  gen_pack_helpers_(), gen_init_helpers_() {}
+struct ProtobufCFileOptionsDefaultTypeInternal {
+  

[PATCH] c++: ICE during aggr CTAD for member tmpl [PR105476]

2022-05-04 Thread Patrick Palka via Gcc-patches
Here we're crashing from maybe_aggr_guide ultimately because
processing_template_decl isn't set when partially instantiating the
guide's parameter list.  This causes us to prematurely force completion
of the dependent type Visitor_functior, which fails and results in
an unexpected error_mark_node.

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

PR c++/105476

gcc/cp/ChangeLog:

* pt.cc (maybe_aggr_guide): Set processing_template_decl when
partially instantiating the guide's parameter list.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/class-deduction-aggr13.C: New test.
* g++.dg/cpp2a/class-deduction-aggr13a.C: New test.
---
 gcc/cp/pt.cc   |  6 +-
 .../g++.dg/cpp2a/class-deduction-aggr13.C  | 11 +++
 .../g++.dg/cpp2a/class-deduction-aggr13a.C | 18 ++
 3 files changed, 34 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr13.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr13a.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index ac002907a41..2bec47dc295 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -29569,7 +29569,11 @@ maybe_aggr_guide (tree tmpl, tree init, 
vec *args)
 PARMS, so that its template level is properly reduced and we don't get
 mismatches when deducing types using the guide with PARMS.  */
   if (member_template_p)
-   parms = tsubst (parms, DECL_TI_ARGS (tmpl), complain, init);
+   {
+ ++processing_template_decl;
+ parms = tsubst (parms, DECL_TI_ARGS (tmpl), complain, init);
+ --processing_template_decl;
+   }
 }
   else if (TREE_CODE (init) == TREE_LIST)
 {
diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr13.C 
b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr13.C
new file mode 100644
index 000..aa8032c60b5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr13.C
@@ -0,0 +1,11 @@
+// PR c++/105476
+// { dg-do compile { target c++20 } }
+
+template struct Visitor_functor;
+
+template struct Events {
+  template struct Visitor : Visitor_functor::type_t... { };
+};
+
+using ev_t = Events;
+ev_t::Visitor v = { {} }; // { dg-error "too many initializers" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr13a.C 
b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr13a.C
new file mode 100644
index 000..69ae5dd4b60
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr13a.C
@@ -0,0 +1,18 @@
+// PR c++/105476
+// { dg-do compile { target c++20 } }
+// A valid version of class-deduction-aggr13.C.
+
+template struct Visitor_functor;
+
+template<> struct Visitor_functor {
+  using type_t = int;
+};
+
+template struct Events {
+  template struct Visitor {
+Visitor_functor::type_t t;
+  };
+};
+
+using ev_t = Events;
+ev_t::Visitor v = { {} };
-- 
2.36.0.44.g0f828332d5



[PATCH] c++: make finish non_static_data_member SFINAE friendly [PR105351]

2022-05-03 Thread Patrick Palka via Gcc-patches
Here, since finish_non_static_data_member isn't SFINAE friendly, we
incorrectly emit an error during overload resolution:

sfinae33.C: In substitution of ‘template A f() [with T = B]’:
sfinae33.C:11:7:   required from here
sfinae33.C:5:31: error: invalid use of non-static data member ‘B::value’
5 | template A f();
  |   ^

This patch fixes this by making the function SFINAE friendly in the
usual way: give it a complain parameter, check it before emitting an
error, and pass it through appropriately.

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

PR c++/105351

gcc/cp/ChangeLog:

* cp-tree.h (finish_non_static_data_member): Add defaulted
complain parameter.
* pt.cc (tsubst_copy_and_build): Pass complain to
finish_non_static_data_member.
* semantics.cc (finish_non_static_data_member): Respect complain
parameter.
(finish_qualified_id_expr): Pass complain to
finish_non_static_data_member.

gcc/testsuite/ChangeLog:

* g++.dg/template/sfinae33.C: New test.
---
 gcc/cp/cp-tree.h |  3 ++-
 gcc/cp/pt.cc |  3 ++-
 gcc/cp/semantics.cc  | 27 ++--
 gcc/testsuite/g++.dg/template/sfinae33.C | 12 +++
 4 files changed, 32 insertions(+), 13 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/sfinae33.C

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 7217768..b29e60ee52f 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7615,7 +7615,8 @@ inline tree force_paren_expr_uneval   (tree t)
 { return force_paren_expr (t, true); }
 extern tree maybe_undo_parenthesized_ref   (tree);
 extern tree maybe_strip_ref_conversion (tree);
-extern tree finish_non_static_data_member   (tree, tree, tree);
+extern tree finish_non_static_data_member   (tree, tree, tree,
+tsubst_flags_t = 
tf_warning_or_error);
 extern tree begin_stmt_expr(void);
 extern tree finish_stmt_expr_expr  (tree, tree);
 extern tree finish_stmt_expr   (tree, bool);
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 81c3c598c71..f96f8e31885 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -21059,7 +21059,8 @@ tsubst_copy_and_build (tree t,
  }
else if (TREE_CODE (member) == FIELD_DECL)
  {
-   r = finish_non_static_data_member (member, object, NULL_TREE);
+   r = finish_non_static_data_member (member, object, NULL_TREE,
+  complain);
if (TREE_CODE (r) == COMPONENT_REF)
  REF_PARENTHESIZED_P (r) = REF_PARENTHESIZED_P (t);
RETURN (r);
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 377f61113c0..bfb737f665b 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -2141,7 +2141,8 @@ finish_parenthesized_expr (cp_expr expr)
preceded by `.' or `->'.  */
 
 tree
-finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
+finish_non_static_data_member (tree decl, tree object, tree qualifying_scope,
+  tsubst_flags_t complain /* = tf_warning_or_error 
*/)
 {
   gcc_assert (TREE_CODE (decl) == FIELD_DECL);
   bool try_omp_private = !object && omp_private_member_map;
@@ -2172,12 +2173,15 @@ finish_non_static_data_member (tree decl, tree object, 
tree qualifying_scope)
   if (is_dummy_object (object) && cp_unevaluated_operand == 0
   && (!processing_template_decl || !current_class_ref))
 {
-  if (current_function_decl
- && DECL_STATIC_FUNCTION_P (current_function_decl))
-   error ("invalid use of member %qD in static member function", decl);
-  else
-   error ("invalid use of non-static data member %qD", decl);
-  inform (DECL_SOURCE_LOCATION (decl), "declared here");
+  if (complain & tf_error)
+   {
+ if (current_function_decl
+ && DECL_STATIC_FUNCTION_P (current_function_decl))
+   error ("invalid use of member %qD in static member function", decl);
+ else
+   error ("invalid use of non-static data member %qD", decl);
+ inform (DECL_SOURCE_LOCATION (decl), "declared here");
+   }
 
   return error_mark_node;
 }
@@ -2219,8 +2223,9 @@ finish_non_static_data_member (tree decl, tree object, 
tree qualifying_scope)
 {
   tree access_type = TREE_TYPE (object);
 
-  perform_or_defer_access_check (TYPE_BINFO (access_type), decl,
-decl, tf_warning_or_error);
+  if (!perform_or_defer_access_check (TYPE_BINFO (access_type), decl,
+ decl, complain))
+   return error_mark_node;
 
   /* If the data member was named `C::M', convert `*this' to `C'
 first.  */
@@ -2234,7 +2239,7 @@ 

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

2022-05-02 Thread Patrick Palka via Gcc-patches
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.  But for a
partial specialization, we can assume the specialized type is valid (as
a consequence of constraints being checked only when necessary), so we
arguably should check the constraints on a partial specialization more
specifically in the context of the specialized type, not the template.

This patch implements this by substituting and setting the access
context appropriately in satisfy_declaration_constraints.  Note that
setting the access context in this case is somewhat redundant since the
relevant caller most_specialized_partial_spec will already have set the
access context to the specialiation, but this redundancy should be harmless.

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk and perhaps 12.2 (after the branch is thawed)?

PR c++/105220

gcc/cp/ChangeLog:

* constraint.cc (satisfy_declaration_constraints): When checking
the constraints of a partial template specialization, do so in
the context of the specialized type not the template.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts-partial-spec12.C: New test.
---
 gcc/cp/constraint.cc  | 17 ++---
 .../g++.dg/cpp2a/concepts-partial-spec12.C| 19 +++
 2 files changed, 33 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec12.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 94f6222b436..772f8532b47 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3253,11 +3253,22 @@ satisfy_declaration_constraints (tree t, tree args, 
sat_info info)
 {
   if (!push_tinst_level (t, args))
return result;
-  tree pattern = DECL_TEMPLATE_RESULT (t);
+  tree ascope = DECL_TEMPLATE_RESULT (t);
+  if (CLASS_TYPE_P (TREE_TYPE (t))
+ && CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (t)))
+   {
+ gcc_checking_assert (t == most_general_template (t));
+ /* When checking the constraints on a partial specialization,
+do so in the context of the specialized type, not the template.
+This substitution should always succeed since we shouldn't
+be checking constraints thereof unless the specialized type
+is valid.  */
+ ascope = tsubst (ascope, args, tf_none, info.in_decl);
+   }
   push_to_top_level ();
-  push_access_scope (pattern);
+  push_access_scope (ascope);
   result = satisfy_normalized_constraints (norm, args, info);
-  pop_access_scope (pattern);
+  pop_access_scope (ascope);
   pop_from_top_level ();
   pop_tinst_level ();
 }
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec12.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec12.C
new file mode 100644
index 000..641d456722d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec12.C
@@ -0,0 +1,19 @@
+// PR c++/105220
+// { dg-do compile { target c++20 } }
+
+template
+concept fooable = requires(T t) { t.foo(); };
+
+template
+struct A;// #1, incomplete
+
+template
+struct A { }; // #2
+
+struct B {
+private:
+  friend struct A;
+  void foo();
+};
+
+template struct A; // OK, B::foo() is accessible from #2
-- 
2.36.0.44.g0f828332d5



[PATCH 2/2] libstdc++: Don't use std::tolower in [PR103911]

2022-05-01 Thread Patrick Palka via Gcc-patches
As in r12-6281-gc83ecfbe74a5cf for std::isdigit,  shouldn't
use std::tolower either I think.

Tested on x86_64-pc-linux-gnu, does this look OK for trunk/11 and the
12 branch after it's thawed?

PR libstdc++/103911

libstdc++-v3/ChangeLog:

* src/c++17/floating_from_chars.cc (find_end_of_float): Accept
two possible delimeters for the exponent part in the form of a
(possibly NULL) string of length two.  Don't use std::tolower.
(pattern): Adjust calls to find_end_of_float accordingly.
---
 libstdc++-v3/src/c++17/floating_from_chars.cc | 11 +--
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/libstdc++-v3/src/c++17/floating_from_chars.cc 
b/libstdc++-v3/src/c++17/floating_from_chars.cc
index e7f3a58cf18..5d2a931d5dd 100644
--- a/libstdc++-v3/src/c++17/floating_from_chars.cc
+++ b/libstdc++-v3/src/c++17/floating_from_chars.cc
@@ -40,7 +40,6 @@
 #include 
 #include 
 #include 
-#include 
 #include 
 #include 
 #if _GLIBCXX_HAVE_XLOCALE_H
@@ -142,10 +141,10 @@ namespace
 
   // Find initial portion of [first, last) containing a floating-point number.
   // The string `digits` is either `dec_digits` or `hex_digits`
-  // and `exp` is 'e' or 'p' or '\0'.
+  // and `exp` is "eE", "pP" or NULL.
   const char*
   find_end_of_float(const char* first, const char* last, const char* digits,
-   char exp)
+   const char *exp)
   {
 while (first < last && strchr(digits, *first) != nullptr)
   ++first;
@@ -155,7 +154,7 @@ namespace
while (first < last && strchr(digits, *first))
  ++first;
   }
-if (first < last && exp != 0 && std::tolower((unsigned char)*first) == exp)
+if (first < last && exp != nullptr && (*first == exp[0] || *first == 
exp[1]))
   {
++first;
if (first < last && (*first == '-' || *first == '+'))
@@ -237,7 +236,7 @@ namespace
 
if ((last - first + 2) > buffer_resource::guaranteed_capacity())
  {
-   last = find_end_of_float(first + neg, last, digits, 'p');
+   last = find_end_of_float(first + neg, last, digits, "pP");
 #ifndef __cpp_exceptions
if ((last - first + 2) > buffer_resource::guaranteed_capacity())
  {
@@ -261,7 +260,7 @@ namespace
if ((last - first) > buffer_resource::guaranteed_capacity())
  {
last = find_end_of_float(first + neg, last, digits,
-"e"[fmt == chars_format::fixed]);
+fmt == chars_format::fixed ? nullptr : 
"eE");
 #ifndef __cpp_exceptions
if ((last - first) > buffer_resource::guaranteed_capacity())
  {
-- 
2.36.0.44.g0f828332d5



[PATCH 1/2] libstdc++: case-sensitivity in hexfloat std::from_chars [PR105441]

2022-05-01 Thread Patrick Palka via Gcc-patches
The hexfloat parser for binary32/64 added in r12-6645-gcc3bf3404e4b1c
overlooked that the exponent part can also begin with an uppercase 'P'.

Tested on x86_64-pc-linux-gnu, does this look OK for trunk/11, and possibly the
12 branch now for 12.1?

PR libstdc++/105441

libstdc++-v3/ChangeLog:

* src/c++17/floating_from_chars.cc (__floating_from_chars_hex):
Also accept 'P' as the start of the exponent.
* testsuite/20_util/from_chars/7.cc: Add corresponding testcase.
---
 libstdc++-v3/src/c++17/floating_from_chars.cc  | 2 +-
 libstdc++-v3/testsuite/20_util/from_chars/7.cc | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/src/c++17/floating_from_chars.cc 
b/libstdc++-v3/src/c++17/floating_from_chars.cc
index 13de1e346ab..e7f3a58cf18 100644
--- a/libstdc++-v3/src/c++17/floating_from_chars.cc
+++ b/libstdc++-v3/src/c++17/floating_from_chars.cc
@@ -664,7 +664,7 @@ namespace
 
 // Parse the written exponent.
 int written_exponent = 0;
-if (first != last && *first == 'p')
+if (first != last && (*first == 'p' || *first == 'P'))
   {
// Tentatively consume the 'p' and try to parse a decimal number.
const char* const fallback_first = first;
diff --git a/libstdc++-v3/testsuite/20_util/from_chars/7.cc 
b/libstdc++-v3/testsuite/20_util/from_chars/7.cc
index 2a78c7441e2..1aa9b230531 100644
--- a/libstdc++-v3/testsuite/20_util/from_chars/7.cc
+++ b/libstdc++-v3/testsuite/20_util/from_chars/7.cc
@@ -96,6 +96,7 @@ constexpr testcase testcases[] = {
   { "1p-1", 4, {}, 0x1p-1 },
   { "0", 1, {}, 0.0 },
   { "A", 1, {}, 0xA },
+  { "1.ABCDEFP+10", 12, {}, 0x1.ABCDEFP+10 },
   { "-1", 2, {}, -1.0 },
   { "-0", 2, {}, -0.0 },
   { "42", 2, {}, 0x42p0 },
-- 
2.36.0.44.g0f828332d5



Re: [PATCH] gengtype: remove "tree_exp" special attribute

2022-04-30 Thread Patrick Palka via Gcc-patches
On Wed, Dec 15, 2021 at 5:10 PM Jason Merrill  wrote:
>
> On 12/10/21 10:41, Patrick Palka wrote:
> > The function comment for adjust_field_tree_exp says this special case
> > is for handling trees whose operands may contain pointers to RTL instead
> > of to trees.  But ever since r0-59671, which fixed/removed the last two
> > tree codes for which this was possible (GOTO_SUBROUTINE_EXPR and
> > WITH_CLEANUP_EXPR), this special attribute is largely a no-op.
> >
> > This patch removes it and instead just annotates struct tree_exp
> > with the "length" attribute directly.  Not sure it makes a difference,
> > but I use %h instead of %0 in the "length" attribute to be consistent
> > with other structures' "length" attributes within tree-core.h.
> >
> > This changes the code generated for TS_EXP handling in gt-cp-tree.h from:
> >
> >case TS_EXP:
> >  gt_ggc_m_9tree_node ((*x).generic.exp.typed.type);
> >  switch ((int) (TREE_CODE ((tree) &(*x
> >{
> >default:
> >   {
> > size_t i3;
> > size_t l3 = (size_t)(TREE_OPERAND_LENGTH ((tree) &(*x)));
> > for (i3 = 0; i3 != l3; i3++) {
> >   gt_ggc_m_9tree_node ((*x).generic.exp.operands[i3]);
> > }
> >   }
> >   break;
> >}
> >  break;
> >
> > to:
> >
> >case TS_EXP:
> >  {
> >size_t l3 = (size_t)(TREE_OPERAND_LENGTH 
> > ((tree)&((*x).generic.exp)));
> >gt_ggc_m_9tree_node ((*x).generic.exp.typed.type);
> >{
> >   size_t i3;
> >   for (i3 = 0; i3 != l3; i3++) {
> > gt_ggc_m_9tree_node ((*x).generic.exp.operands[i3]);
> >   }
> >}
> >  }
> >
> > which seems equivalent and simpler.
> >
> > Boostrapped and regtested on x86_64-pc-linux-gnu, does this look OK for 
> > trunk?
>
> OK.

Thanks, I just pushed this patch to trunk now that we're back in stage1.

>
> > gcc/ChangeLog:
> >
> >   * gengtype.c (adjust_field_tree_exp): Remove.
> >   (adjust_field_type): Don't handle the "tree_exp" special attribute.
> >   * tree-core.h (struct tree_exp): Replace special and desc
> >   attributes with length.
> > ---
> >   gcc/gengtype.c  | 35 +--
> >   gcc/tree-core.h |  4 +---
> >   2 files changed, 2 insertions(+), 37 deletions(-)
> >
> > diff --git a/gcc/gengtype.c b/gcc/gengtype.c
> > index db218a7bce7..2dc443175fa 100644
> > --- a/gcc/gengtype.c
> > +++ b/gcc/gengtype.c
> > @@ -511,7 +511,6 @@ pair_p typedefs = NULL;
> >   type_p structures = NULL;
> >   pair_p variables = NULL;
> >
> > -static type_p adjust_field_tree_exp (type_p t, options_p opt);
> >   static type_p adjust_field_rtx_def (type_p t, options_p opt);
> >
> >   /* Define S as a typedef to T at POS.  */
> > @@ -1384,36 +1383,6 @@ adjust_field_rtx_def (type_p t, options_p ARG_UNUSED 
> > (opt))
> >   nodot, NULL);
> >   }
> >
> > -/* Handle `special("tree_exp")'.  This is a special case for
> > -   field `operands' of struct tree_exp, which although it claims to contain
> > -   pointers to trees, actually sometimes contains pointers to RTL too.
> > -   Passed T, the old type of the field, and OPT its options.  Returns
> > -   a new type for the field.  */
> > -
> > -static type_p
> > -adjust_field_tree_exp (type_p t, options_p opt ATTRIBUTE_UNUSED)
> > -{
> > -  pair_p flds;
> > -  options_p nodot;
> > -
> > -  if (t->kind != TYPE_ARRAY)
> > -{
> > -  error_at_line (_line,
> > -  "special `tree_exp' must be applied to an array");
> > -  return _type;
> > -}
> > -
> > -  nodot = create_string_option (NULL, "dot", "");
> > -
> > -  flds = create_field (NULL, t, "");
> > -  flds->opt = create_string_option (nodot, "length",
> > - "TREE_OPERAND_LENGTH ((tree) &%0)");
> > -  flds->opt = create_string_option (flds->opt, "default", "");
> > -
> > -  return new_structure ("tree_exp_subunion", TYPE_UNION, _line, flds,
> > - nodot, NULL);
> > -}
> > -
> >   /* Perform any special processing on a type T, about to become the type
> >  of a field.  Return the appropriate type for the field.
> >  

[PATCH] c++: partial ordering and dependent operator expr [PR105425]

2022-04-28 Thread Patrick Palka via Gcc-patches
Here ever since r12-6022-gbb2a7f80a98de3 we stopped deeming the partial
specialization #2 to be more specialized than #1 ultimately because
dependent operator expressions now have a DEPENDENT_OPERATOR_TYPE type
instead of an empty type, and this made unify stop deducing T(2) == 1
for K during partial ordering for #1 and #2.

This minimal patch fixes this by making the relevant code in unify
treat DEPENDENT_OPERATOR_TYPE like an empty type.

Bootstrapped and regtested on x86_64-pc-linux-gnu, and preapproved for
trunk by Jason off-list.  Does this also look OK for the 12 branch?

PR c++/105425

gcc/cp/ChangeLog:

* pt.cc (unify) : Treat
DEPENDENT_OPERATOR_TYPE like an empty type.

gcc/testsuite/ChangeLog:

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

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 3cf1d7af8d2..cf24d482488 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -24276,7 +24276,8 @@ unify (tree tparms, tree targs, tree parm, tree arg, 
int strict,
}
}
 
-  if (!TREE_TYPE (arg))
+  if (!TREE_TYPE (arg)
+ || TREE_CODE (TREE_TYPE (arg)) == DEPENDENT_OPERATOR_TYPE)
/* Template-parameter dependent expression.  Just accept it for now.
   It will later be processed in convert_template_argument.  */
;
diff --git a/gcc/testsuite/g++.dg/template/partial-specialization13.C 
b/gcc/testsuite/g++.dg/template/partial-specialization13.C
new file mode 100644
index 000..e0a115cd06c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/partial-specialization13.C
@@ -0,0 +1,10 @@
+// PR c++/105425
+// { dg-do compile { target c++11 } }
+
+template struct when;
+template struct A;
+template struct A>;// #1
+template struct A> {}; // #2
+A> a1; // { dg-error "incomplete" }
+A> a2;
+A> a3;
-- 
2.36.0.rc2.10.g1ac7422e39



Re: [PATCH v2] c++: ICE with temporary of class type in DMI [PR100252]

2022-04-28 Thread Patrick Palka via Gcc-patches
On Wed, 27 Apr 2022, Marek Polacek wrote:

> On Wed, Apr 27, 2022 at 11:00:46AM -0400, Patrick Palka wrote:
> > On Tue, 26 Apr 2022, Marek Polacek wrote:
> > 
> > > Consider
> > > 
> > >   struct A {
> > > int x;
> > > int y = x;
> > >   };
> > > 
> > >   struct B {
> > > int x = 0;
> > > int y = A{x}.y; // #1
> > >   };
> > > 
> > > where for #1 we end up with
> > > 
> > >   {.x=(&)->x, .y=(& > > A>)->x}
> > > 
> > > that is, two PLACEHOLDER_EXPRs for different types on the same level in
> > > a {}.  This crashes because our CONSTRUCTOR_PLACEHOLDER_BOUNDARY 
> > > mechanism to
> > > avoid replacing unrelated PLACEHOLDER_EXPRs cannot deal with it.
> > > 
> > > Here's why we wound up with those PLACEHOLDER_EXPRs: When we're performing
> > > cp_parser_late_parsing_nsdmi for "int y = A{x}.y;" we use 
> > > finish_compound_literal
> > > on type=A, compound_literal={((struct B *) this)->x}.  When digesting this
> > > initializer, we call get_nsdmi which creates a PLACEHOLDER_EXPR for A -- 
> > > we don't
> > > have any object to refer to yet.  After digesting, we have
> > > 
> > >   {.x=((struct B *) this)->x, .y=(&)->x}
> > > 
> > > and since we've created a PLACEHOLDER_EXPR inside it, we marked the whole 
> > > ctor
> > > CONSTRUCTOR_PLACEHOLDER_BOUNDARY.  f_c_l creates a TARGET_EXPR and returns
> > > 
> > >   TARGET_EXPR x, .y=(& > > struct A>)->x}>
> > > 
> > > Then we get to
> > > 
> > >   B b = {};
> > > 
> > > and call store_init_value, which digest the {}, which produces
> > > 
> > >   {.x=NON_LVALUE_EXPR <0>, .y=(TARGET_EXPR  > > {.x=(&)->x, .y=(& > > A>)->x}>).y}
> > > 
> > > The call to replace_placeholders in store_init_value will not do anything:
> > > we've marked the inner { } CONSTRUCTOR_PLACEHOLDER_BOUNDARY, and it's only
> > > a sub-expression, so replace_placeholders does nothing, so the  > > struct B>
> > > stays even though now is the perfect time to replace it because we have an
> > > object for it: 'b'.
> > > 
> > > Later, in cp_gimplify_init_expr the *expr_p is
> > > 
> > >   D.2395 = {.x=(&)->x, .y=(& > > struct A>)->x}
> > > 
> > > where D.2395 is of type A, but we crash because we hit , 
> > > which
> > > has a different type.
> > > 
> > > My idea was to replace  with D.2384 in f_c_l after creating 
> > > the
> > > TARGET_EXPR because that means we have an object we can refer to.  Then 
> > > clear
> > > CONSTRUCTOR_PLACEHOLDER_BOUNDARY because we no longer have a 
> > > PLACEHOLDER_EXPR
> > > in the {}.  Then store_init_value will be able to replace  
> > > with
> > > 'b', and we should be good to go.
> > 
> > Makes sense to me.  It seems all was well until break_out_target_exprs,
> > called from get_nsdmi for B::y, replaced the 'this' in the initializer
> > 
> >   (TARGET_EXPR x, .y=(& > struct A>)->x}>).y;
> > 
> > with a PLACEHOLDER_EXPR;
> > 
> >   (TARGET_EXPR )->x, 
> > .y=(&)->x}>).y;
> > 
> > This seems to be the wrong thing to do when the 'this' appears inside a
> > CONSTRUCTOR_PLACEHOLDER_BOUNDARY constructor because the new
> > PLACEHOLDER_EXPR then can't be resolved correctly.
> 
> Exactly.
> 
> > So in light of this I wonder if we should instead perform this handling
> > you added to finish_compound_literal in break_out_target_exprs /
> > bot_manip instead?
> 
> Unfortunately that causes an ICE in gimplify_var_or_parm_decl on the new
> testcase I've added here.  bot_manip is a different context and so I can't
> use parsing_nsdmi anymore, and it seems we'd replace the placeholders too
> aggressively in bot_manip.  So I'm not sure if that's the best place.

Ah :/ good catch...

FWIW the transformation itself (doing replace_placeholders followed by
clearing CONSTRUCTOR_PLACEHOLDER_BOUNDARY) makes sense to me, and I'm
happy with doing it in finish_compound_literal when parsing_nsdmi, so
the patch LGTM.

(I guess we could also consider doing the transformation in get_nsdmi or
digest_nsdmi_init via cp_walk_tree, but I don't have a preference either way..)

> 
> -- >8 --
> Consider
> 
>   struct A {
> int x;
> int y = x;
>   };

Re: [PATCH] c++: ICE with temporary of class type in DMI [PR100252]

2022-04-27 Thread Patrick Palka via Gcc-patches
On Tue, 26 Apr 2022, Marek Polacek wrote:

> Consider
> 
>   struct A {
> int x;
> int y = x;
>   };
> 
>   struct B {
> int x = 0;
> int y = A{x}.y; // #1
>   };
> 
> where for #1 we end up with
> 
>   {.x=(&)->x, .y=(&)->x}
> 
> that is, two PLACEHOLDER_EXPRs for different types on the same level in
> a {}.  This crashes because our CONSTRUCTOR_PLACEHOLDER_BOUNDARY mechanism to
> avoid replacing unrelated PLACEHOLDER_EXPRs cannot deal with it.
> 
> Here's why we wound up with those PLACEHOLDER_EXPRs: When we're performing
> cp_parser_late_parsing_nsdmi for "int y = A{x}.y;" we use 
> finish_compound_literal
> on type=A, compound_literal={((struct B *) this)->x}.  When digesting this
> initializer, we call get_nsdmi which creates a PLACEHOLDER_EXPR for A -- we 
> don't
> have any object to refer to yet.  After digesting, we have
> 
>   {.x=((struct B *) this)->x, .y=(&)->x}
> 
> and since we've created a PLACEHOLDER_EXPR inside it, we marked the whole ctor
> CONSTRUCTOR_PLACEHOLDER_BOUNDARY.  f_c_l creates a TARGET_EXPR and returns
> 
>   TARGET_EXPR x, .y=(& struct A>)->x}>
> 
> Then we get to
> 
>   B b = {};
> 
> and call store_init_value, which digest the {}, which produces
> 
>   {.x=NON_LVALUE_EXPR <0>, .y=(TARGET_EXPR  struct B>)->x, .y=(&)->x}>).y}
> 
> The call to replace_placeholders in store_init_value will not do anything:
> we've marked the inner { } CONSTRUCTOR_PLACEHOLDER_BOUNDARY, and it's only
> a sub-expression, so replace_placeholders does nothing, so the 
> stays even though now is the perfect time to replace it because we have an
> object for it: 'b'.
> 
> Later, in cp_gimplify_init_expr the *expr_p is
> 
>   D.2395 = {.x=(&)->x, .y=(& struct A>)->x}
> 
> where D.2395 is of type A, but we crash because we hit , which
> has a different type.
> 
> My idea was to replace  with D.2384 in f_c_l after creating the
> TARGET_EXPR because that means we have an object we can refer to.  Then clear
> CONSTRUCTOR_PLACEHOLDER_BOUNDARY because we no longer have a PLACEHOLDER_EXPR
> in the {}.  Then store_init_value will be able to replace  with
> 'b', and we should be good to go.

Makes sense to me.  It seems all was well until break_out_target_exprs,
called from get_nsdmi for B::y, replaced the 'this' in the initializer

  (TARGET_EXPR x, .y=(&)->x}>).y;

with a PLACEHOLDER_EXPR;

  (TARGET_EXPR )->x, 
.y=(&)->x}>).y;

This seems to be the wrong thing to do when the 'this' appears inside a
CONSTRUCTOR_PLACEHOLDER_BOUNDARY constructor because the new
PLACEHOLDER_EXPR then can't be resolved correctly.

So in light of this I wonder if we should instead perform this handling
you added to finish_compound_literal in break_out_target_exprs /
bot_manip instead?

> 
> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/11.4?
> 
>   PR c++/100252
> 
> gcc/cp/ChangeLog:
> 
>   * semantics.cc (finish_compound_literal): replace_placeholders after
>   creating the TARGET_EXPR.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp1y/nsdmi-aggr14.C: New test.
> ---
>  gcc/cp/semantics.cc   | 31 +++
>  gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr14.C | 46 +++
>  2 files changed, 77 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr14.C
> 
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index ab48f11c9be..770369458bb 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -3296,6 +3296,37 @@ finish_compound_literal (tree type, tree 
> compound_literal,
>if (TREE_CODE (compound_literal) == CONSTRUCTOR)
>   TREE_HAS_CONSTRUCTOR (compound_literal) = false;
>compound_literal = get_target_expr_sfinae (compound_literal, complain);
> +  /* We may have A{} in a NSDMI.  */
> +  if (parsing_nsdmi ())
> + {
> +   /* Digesting the {} could have introduced a PLACEHOLDER_EXPR
> +  referring to A.  Now that we've built up a TARGET_EXPR, we
> +  have an object we can refer to.  The reason we bother doing
> +  this here is for code like
> +
> +struct A {
> +  int x;
> +  int y = x;
> +};
> +
> +struct B {
> +  int x = 0;
> +  int y = A{x}.y; // #1
> +};
> +
> +  where in #1 we don't want to end up with two PLACEHOLDER_EXPRs
> +  for different types on the same level in a {} as in 100252.  */
> +   tree init = TARGET_EXPR_INITIAL (compound_literal);
> +   if (TREE_CODE (init) == CONSTRUCTOR
> +   && CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init))
> + {
> +   tree obj = TARGET_EXPR_SLOT (compound_literal);
> +   replace_placeholders (compound_literal, obj);
> +   /* We should have dealt with the PLACEHOLDER_EXPRs.  */
> +   CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init) = false;
> +   gcc_checking_assert (!find_placeholders (init));
> + }
> + }
>  }
>else
>  /* For 

Re: [PATCH] c++: enum in generic lambda at global scope [PR105398]

2022-04-27 Thread Patrick Palka via Gcc-patches
On Tue, 26 Apr 2022, Marek Polacek via Gcc-patches wrote:

> We crash compiling this test since r11-7993 which changed
> lookup_template_class_1 so that we only call tsubst_enum when
> 
>   !uses_template_parms (current_nonlambda_scope ())
> 
> But here current_nonlambda_scope () is the global NAMESPACE_DECL ::, which
> doesn't have a type, therefore is considered type-dependent.  So we don't
> call tsubst_enum, and crash in tsubst_copy/CONST_DECL because we didn't
> find the e1 enumerator.
> 
> I don't think any namespace can depend on any template parameter, so
> this patch tweaks uses_template_parms.
> 
> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/11?
> 
>   PR c++/105398
> 
> gcc/cp/ChangeLog:
> 
>   * pt.cc (uses_template_parms): Return false for any NAMESPACE_DECL.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp1y/lambda-generic-enum2.C: New test.
> ---
>  gcc/cp/pt.cc  |  2 +-
>  gcc/testsuite/g++.dg/cpp1y/lambda-generic-enum2.C | 15 +++
>  2 files changed, 16 insertions(+), 1 deletion(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-enum2.C
> 
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 3cf1d7af8d2..e785c5db142 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -10905,7 +10905,7 @@ uses_template_parms (tree t)
>  || uses_template_parms (TREE_CHAIN (t)));
>else if (TREE_CODE (t) == TYPE_DECL)
>  dependent_p = dependent_type_p (TREE_TYPE (t));
> -  else if (t == error_mark_node)
> +  else if (t == error_mark_node || TREE_CODE (t) == NAMESPACE_DECL)

LGTM.  In passing, perhaps we should move this t == error_mark_node test
to the beginning of the function alongside the t == NULL_TREE test?

>  dependent_p = false;
>else
>  dependent_p = instantiation_dependent_expression_p (t);
> diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-enum2.C 
> b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-enum2.C
> new file mode 100644
> index 000..77cf0bb9d02
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-enum2.C
> @@ -0,0 +1,15 @@
> +// PR c++/105398
> +// { dg-do compile { target c++14 } }
> +
> +auto f = [](auto &) {
> +enum E { _,e3,e2,e1,C4,C3,C2,C1 };
> +static constexpr int x_coeffs[3][4] = {
> +{e1,C2,C3,C4},
> +{e2,C1,C3,C4},
> +{e3,C1,C2,C4},
> +};
> +};
> +
> +int main() {
> +f(0);
> +}
> 
> base-commit: 9ace5d4dab2ab39072b0f07089621a823580f27c
> -- 
> 2.35.1
> 
> 



[PATCH] c++: decltype of non-dependent call of class type [PR105386]

2022-04-26 Thread Patrick Palka via Gcc-patches
We need to pass tf_decltype when instantiating a non-dependent decltype
operand, like tsubst does in the dependent case, so that we avoid
materializing a temporary for a prvalue operand.

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

PR c++/105386

gcc/cp/ChangeLog:

* semantics.cc (finish_decltype_type): Pass tf_decltype to
instantiate_non_dependent_expr_sfinae.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/decltype81.C: New test.
---
 gcc/cp/semantics.cc |  2 +-
 gcc/testsuite/g++.dg/cpp0x/decltype81.C | 15 +++
 2 files changed, 16 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/decltype81.C

diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index f08c0b6281f..ab48f11c9be 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -11252,7 +11252,7 @@ finish_decltype_type (tree expr, bool 
id_expression_or_member_access_p,
 }
   else if (processing_template_decl)
 {
-  expr = instantiate_non_dependent_expr_sfinae (expr, complain);
+  expr = instantiate_non_dependent_expr_sfinae (expr, 
complain|tf_decltype);
   if (expr == error_mark_node)
return error_mark_node;
   /* Keep processing_template_decl cleared for the rest of the function
diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype81.C 
b/gcc/testsuite/g++.dg/cpp0x/decltype81.C
new file mode 100644
index 000..7d25db39d9c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/decltype81.C
@@ -0,0 +1,15 @@
+// PR c++/105386
+// { dg-do compile { target c++11 } }
+
+template struct NoInst {
+  static_assert(sizeof(T) == , "NoInst instantiated");
+};
+
+template NoInst f(T);
+
+template
+struct A {
+  using type = decltype(f(0));
+};
+
+A a;
-- 
2.36.0.rc2.10.g1ac7422e39



Re: [PATCH] c++: partial ordering with dependent NTTP type [PR105289]

2022-04-25 Thread Patrick Palka via Gcc-patches
On Mon, 25 Apr 2022, Jason Merrill wrote:

> On 4/22/22 15:27, Patrick Palka wrote:
> > On Fri, 22 Apr 2022, Patrick Palka wrote:
> > 
> > > Here ever since r11-6483-ge2e2f3f2c9400f we're rejecting and crashing
> > > (respectively) on two testcases that we used to accept in C++17 mode.
> > > Both testcases declare partial specializations for which the primary
> > > template contains an NTTP with dependent type, but the correctness of
> > > these partial specializations is unclear according to PR86193.
> > > 
> > > This patch restores the previous C++17 behavior for such partial
> > > specializations by restricting the r11-6483 change to just ordinary
> > > deduction as opposed to deduction for sake of partial ordering.
> > 
> > Note that if we're okay with rejecting such partial specializations even
> > in C++17 mode (and thus deeming PR105289 to be ICE-on-invalid instead of
> > ICE-on-valid), then the fix for the reported ICE is just:
> > 
> > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > index dde62ee052d..6d65f6ad3cf 100644
> > --- a/gcc/cp/pt.cc
> > +++ b/gcc/cp/pt.cc
> > @@ -24299,7 +24299,7 @@ unify (tree tparms, tree targs, tree parm, tree arg,
> > int strict,
> >   /* Now check whether the type of this parameter is still
> >  dependent, and give up if so.  */
> >   ++processing_template_decl;
> > - tparm = tsubst (tparm, targs, tf_none, NULL_TREE);
> > + tparm = tsubst (TREE_TYPE (parm), targs, tf_none, NULL_TREE);
> >   --processing_template_decl;
> >   if (uses_template_parms (tparm))
> > return unify_success (explain_p);
> > 
> > i.e. we need to substitute into the original NTTP type, not into the
> > already substituted NTTP type.
> 
> I'm happy rejecting partial-specialization12.C on that basis.  11 is
> interesting because int is a non-dependent type; it might be worth adding that
> testcase to the DR455 discussion.
> 
> I think let's go with this patch and bump down the "partial specialization
> isn't more specialized" diagnostic from permerror to on-by-default pedwarn.

Ah, sounds good to me. like so?

-- >8 --

Subject: [PATCH] c++: partial ordering with dependent NTTP type [PR105289]

Here ever since r11-6483-ge2e2f3f2c9400f we're rejecting and crashing
on (respectively) two testcases that we used to accept in C++17 mode
since r8-1437-g3da557ec145823.  Both testcases declare a partial
specialization for which the primary template contains an NTTP with
dependent type, but the validity of these partial specializations is
unclear and is the subject of PR86193 / CWG 455.

This patch just fixes the reported ICE in the second testcase.  The bug
was that when checking whether the type of an NTTP uses still-undeduced
parameters, we'd substitute into the previously substituted NTTP type
instead of into the original NTTP type.

And given that the treatment of such partial specializations seems to
be underspecified in the standard, this patch downgrades the general
"not more specialized" diagnostic from a permerror to a pedwarn.

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

PR c++/105289
PR c++/86193

gcc/cp/ChangeLog:

* pt.cc (process_partial_specialization): Downgrade "partial
specialization isn't more specialized" diagnostic from permerror
to an on-by-default pedwarn.
(unify) : When substituting into the
NTTP type a second time, use the original type not the
substituted type.

gcc/testsuite/ChangeLog:

* g++.dg/template/partial-specialization11.C: New test.
* g++.dg/template/partial-specialization12.C: New test.
---
 gcc/cp/pt.cc|  7 ---
 .../g++.dg/template/partial-specialization11.C  | 11 +++
 .../g++.dg/template/partial-specialization12.C  | 13 +
 3 files changed, 28 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/partial-specialization11.C
 create mode 100644 gcc/testsuite/g++.dg/template/partial-specialization12.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index dde62ee052d..7dd9e6788f4 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -5227,8 +5227,9 @@ process_partial_specialization (tree decl)
   && !get_partial_spec_bindings (maintmpl, maintmpl, specargs))
 {
   auto_diagnostic_group d;
-  if (permerror (input_location, "partial specialization %qD is not "
-"more specialized than", decl))
+  if (pedwarn (input_location, 0,
+  "partial specialization %qD is not more specialized than",
+  

Re: [PATCH] c++: partial ordering with dependent NTTP type [PR105289]

2022-04-22 Thread Patrick Palka via Gcc-patches
On Fri, 22 Apr 2022, Patrick Palka wrote:

> Here ever since r11-6483-ge2e2f3f2c9400f we're rejecting and crashing
> (respectively) on two testcases that we used to accept in C++17 mode.
> Both testcases declare partial specializations for which the primary
> template contains an NTTP with dependent type, but the correctness of
> these partial specializations is unclear according to PR86193.
> 
> This patch restores the previous C++17 behavior for such partial
> specializations by restricting the r11-6483 change to just ordinary
> deduction as opposed to deduction for sake of partial ordering.

Note that if we're okay with rejecting such partial specializations even
in C++17 mode (and thus deeming PR105289 to be ICE-on-invalid instead of
ICE-on-valid), then the fix for the reported ICE is just:

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index dde62ee052d..6d65f6ad3cf 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -24299,7 +24299,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, 
int strict,
  /* Now check whether the type of this parameter is still
 dependent, and give up if so.  */
  ++processing_template_decl;
- tparm = tsubst (tparm, targs, tf_none, NULL_TREE);
+ tparm = tsubst (TREE_TYPE (parm), targs, tf_none, NULL_TREE);
  --processing_template_decl;
  if (uses_template_parms (tparm))
return unify_success (explain_p);

i.e. we need to substitute into the original NTTP type, not into the
already substituted NTTP type.

> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk/11?
> 
>   PR c++/105289
>   PR c++/86193
> 
> gcc/cp/ChangeLog:
> 
>   * pt.cc (unify) : Restrict the
>   r11-6483 change to just ordinary deduction for function
>   templates.  When substituting into the NTTP type the second
>   time, use the original type not the substituted type.  Remove
>   now unnecessary level check.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/template/partial5.C: Revert r11-6483 change.
>   * g++.dg/template/partial-specialization11.C: New test.
>   * g++.dg/template/partial-specialization12.C: New test.
> ---
>  gcc/cp/pt.cc  | 25 ---
>  .../template/partial-specialization11.C   | 10 
>  .../template/partial-specialization12.C   | 12 +
>  gcc/testsuite/g++.dg/template/partial5.C  |  2 +-
>  4 files changed, 39 insertions(+), 10 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/template/partial-specialization11.C
>  create mode 100644 gcc/testsuite/g++.dg/template/partial-specialization12.C
> 
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index dde62ee052d..52bd130b7e7 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -24287,8 +24287,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, 
> int strict,
> /* We haven't deduced the type of this parameter yet.  */
> if (cxx_dialect >= cxx17
> /* We deduce from array bounds in try_array_deduction.  */
> -   && !(strict & UNIFY_ALLOW_INTEGER)
> -   && TEMPLATE_PARM_LEVEL (parm) <= TMPL_ARGS_DEPTH (targs))
> +   && !(strict & UNIFY_ALLOW_INTEGER))
>   {
> /* Deduce it from the non-type argument.  As above, ignore
>top-level quals here too.  */
> @@ -24296,13 +24295,21 @@ unify (tree tparms, tree targs, tree parm, tree 
> arg, int strict,
> RECUR_AND_CHECK_FAILURE (tparms, targs,
>  tparm, atype,
>  UNIFY_ALLOW_NONE, explain_p);
> -   /* Now check whether the type of this parameter is still
> -  dependent, and give up if so.  */
> -   ++processing_template_decl;
> -   tparm = tsubst (tparm, targs, tf_none, NULL_TREE);
> -   --processing_template_decl;
> -   if (uses_template_parms (tparm))
> - return unify_success (explain_p);
> +   if (!processing_template_decl
> +   && TPARMS_PRIMARY_TEMPLATE (tparms)
> +   && DECL_FUNCTION_TEMPLATE_P (TPARMS_PRIMARY_TEMPLATE
> +(tparms)))
> + {
> +   /* If the NTTP's type uses still-undeduced template
> +  parameters, then don't unify it now.  This gives
> +  type_unification_real a chance to retry deduction
> +  with default template arguments substituted in.  */
> +   ++processing_template_decl;
> +   tparm = tsubst (TREE_TYPE (parm), targs, tf_none, NULL_TREE);
>

Re: [PATCH] c++: partial ordering with dependent NTTP type [PR105289]

2022-04-22 Thread Patrick Palka via Gcc-patches
Whoops, this patch is identical to
https://gcc.gnu.org/pipermail/gcc-patches/2022-April/593502.html that
I sent about an hour ago, sorry for the noise.

On Fri, Apr 22, 2022 at 2:33 PM Patrick Palka  wrote:
>
> Here ever since r11-6483-ge2e2f3f2c9400f we're rejecting and crashing
> (respectively) on two testcases that we used to accept in C++17 mode.
> Both testcases declare partial specializations for which the primary
> template contains an NTTP with dependent type, but the correctness of
> these partial specializations is unclear according to PR86193.
>
> This patch restores the previous C++17 behavior for such partial
> specializations by restricting the r11-6483 change to just ordinary
> deduction as opposed to deduction for sake of partial ordering.
>
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk/11?
>
> PR c++/105289
> PR c++/86193
>
> gcc/cp/ChangeLog:
>
> * pt.cc (unify) : Restrict the
> r11-6483 change to just ordinary deduction for function
> templates.  When substituting into the NTTP type the second
> time, use the original type not the substituted type.  Remove
> now unnecessary level check.
>
> gcc/testsuite/ChangeLog:
>
> * g++.dg/template/partial5.C: Revert r11-6483 change.
> * g++.dg/template/partial-specialization11.C: New test.
> * g++.dg/template/partial-specialization12.C: New test.
> ---
>  gcc/cp/pt.cc  | 25 ---
>  .../template/partial-specialization11.C   | 10 
>  .../template/partial-specialization12.C   | 12 +
>  gcc/testsuite/g++.dg/template/partial5.C  |  2 +-
>  4 files changed, 39 insertions(+), 10 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/template/partial-specialization11.C
>  create mode 100644 gcc/testsuite/g++.dg/template/partial-specialization12.C
>
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index dde62ee052d..52bd130b7e7 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -24287,8 +24287,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, 
> int strict,
>   /* We haven't deduced the type of this parameter yet.  */
>   if (cxx_dialect >= cxx17
>   /* We deduce from array bounds in try_array_deduction.  */
> - && !(strict & UNIFY_ALLOW_INTEGER)
> - && TEMPLATE_PARM_LEVEL (parm) <= TMPL_ARGS_DEPTH (targs))
> + && !(strict & UNIFY_ALLOW_INTEGER))
> {
>   /* Deduce it from the non-type argument.  As above, ignore
>  top-level quals here too.  */
> @@ -24296,13 +24295,21 @@ unify (tree tparms, tree targs, tree parm, tree 
> arg, int strict,
>   RECUR_AND_CHECK_FAILURE (tparms, targs,
>tparm, atype,
>UNIFY_ALLOW_NONE, explain_p);
> - /* Now check whether the type of this parameter is still
> -dependent, and give up if so.  */
> - ++processing_template_decl;
> - tparm = tsubst (tparm, targs, tf_none, NULL_TREE);
> - --processing_template_decl;
> - if (uses_template_parms (tparm))
> -   return unify_success (explain_p);
> + if (!processing_template_decl
> + && TPARMS_PRIMARY_TEMPLATE (tparms)
> + && DECL_FUNCTION_TEMPLATE_P (TPARMS_PRIMARY_TEMPLATE
> +  (tparms)))
> +   {
> + /* If the NTTP's type uses still-undeduced template
> +parameters, then don't unify it now.  This gives
> +type_unification_real a chance to retry deduction
> +with default template arguments substituted in.  */
> + ++processing_template_decl;
> + tparm = tsubst (TREE_TYPE (parm), targs, tf_none, 
> NULL_TREE);
> + --processing_template_decl;
> + if (uses_template_parms (tparm))
> +   return unify_success (explain_p);
> +   }
> }
>   else
> /* Try again later.  */
> diff --git a/gcc/testsuite/g++.dg/template/partial-specialization11.C 
> b/gcc/testsuite/g++.dg/template/partial-specialization11.C
> new file mode 100644
> index 000..20da407d422
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/template/partial-specialization11.C
> @@ -0,0 +1,10 @@
> +// PR c++/105289
> +
> +template struct value_type;
> +
> +template::type V>
> +struct push_front_vlist;
> +
> +templ

[PATCH] c++: crash with requires-expr and -Wsequence-point [PR105304]

2022-04-22 Thread Patrick Palka via Gcc-patches
Here we're crashing from verify_sequence_points for this requires-expr
condition because it contains a templated CAST_EXPR with empty operand,
and verify_tree doesn't ignore this empty operand only because the
manual tail recursion that it perform for unary expression trees skips
the NULL test.

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

PR c++/105304

gcc/c-family/ChangeLog:

* c-common.cc (verify_tree) [restart]: Move up to before the
NULL test.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts-requires30.C: New test.
---
 gcc/c-family/c-common.cc |  2 +-
 gcc/testsuite/g++.dg/cpp2a/concepts-requires30.C | 10 ++
 2 files changed, 11 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-requires30.C

diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index 70f55f3a346..bb0544eeaea 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -2009,12 +2009,12 @@ verify_tree (tree x, struct tlist **pbefore_sp, struct 
tlist **pno_sp,
   enum tree_code code;
   enum tree_code_class cl;
 
+ restart:
   /* X may be NULL if it is the operand of an empty statement expression
  ({ }).  */
   if (x == NULL)
 return;
 
- restart:
   code = TREE_CODE (x);
   cl = TREE_CODE_CLASS (code);
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires30.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-requires30.C
new file mode 100644
index 000..f500af3f616
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires30.C
@@ -0,0 +1,10 @@
+// PR c++/105304
+// { dg-do compile { target c++20 } }
+// { dg-additional-options "-Wall -Wsequence-point" }
+
+struct A { };
+
+int main() {
+  if (requires { A(); })
+;
+}
-- 
2.36.0.rc2.10.g1ac7422e39



[PATCH] c++: partial ordering with dependent NTTP type [PR105289]

2022-04-22 Thread Patrick Palka via Gcc-patches
Here ever since r11-6483-ge2e2f3f2c9400f we're rejecting and crashing
(respectively) on two testcases that we used to accept in C++17 mode.
Both testcases declare partial specializations for which the primary
template contains an NTTP with dependent type, but the correctness of
these partial specializations is unclear according to PR86193.

This patch restores the previous C++17 behavior for such partial
specializations by restricting the r11-6483 change to just ordinary
deduction as opposed to deduction for sake of partial ordering.

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

PR c++/105289
PR c++/86193

gcc/cp/ChangeLog:

* pt.cc (unify) : Restrict the
r11-6483 change to just ordinary deduction for function
templates.  When substituting into the NTTP type the second
time, use the original type not the substituted type.  Remove
now unnecessary level check.

gcc/testsuite/ChangeLog:

* g++.dg/template/partial5.C: Revert r11-6483 change.
* g++.dg/template/partial-specialization11.C: New test.
* g++.dg/template/partial-specialization12.C: New test.
---
 gcc/cp/pt.cc  | 25 ---
 .../template/partial-specialization11.C   | 10 
 .../template/partial-specialization12.C   | 12 +
 gcc/testsuite/g++.dg/template/partial5.C  |  2 +-
 4 files changed, 39 insertions(+), 10 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/partial-specialization11.C
 create mode 100644 gcc/testsuite/g++.dg/template/partial-specialization12.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index dde62ee052d..52bd130b7e7 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -24287,8 +24287,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, 
int strict,
  /* We haven't deduced the type of this parameter yet.  */
  if (cxx_dialect >= cxx17
  /* We deduce from array bounds in try_array_deduction.  */
- && !(strict & UNIFY_ALLOW_INTEGER)
- && TEMPLATE_PARM_LEVEL (parm) <= TMPL_ARGS_DEPTH (targs))
+ && !(strict & UNIFY_ALLOW_INTEGER))
{
  /* Deduce it from the non-type argument.  As above, ignore
 top-level quals here too.  */
@@ -24296,13 +24295,21 @@ unify (tree tparms, tree targs, tree parm, tree arg, 
int strict,
  RECUR_AND_CHECK_FAILURE (tparms, targs,
   tparm, atype,
   UNIFY_ALLOW_NONE, explain_p);
- /* Now check whether the type of this parameter is still
-dependent, and give up if so.  */
- ++processing_template_decl;
- tparm = tsubst (tparm, targs, tf_none, NULL_TREE);
- --processing_template_decl;
- if (uses_template_parms (tparm))
-   return unify_success (explain_p);
+ if (!processing_template_decl
+ && TPARMS_PRIMARY_TEMPLATE (tparms)
+ && DECL_FUNCTION_TEMPLATE_P (TPARMS_PRIMARY_TEMPLATE
+  (tparms)))
+   {
+ /* If the NTTP's type uses still-undeduced template
+parameters, then don't unify it now.  This gives
+type_unification_real a chance to retry deduction
+with default template arguments substituted in.  */
+ ++processing_template_decl;
+ tparm = tsubst (TREE_TYPE (parm), targs, tf_none, NULL_TREE);
+ --processing_template_decl;
+ if (uses_template_parms (tparm))
+   return unify_success (explain_p);
+   }
}
  else
/* Try again later.  */
diff --git a/gcc/testsuite/g++.dg/template/partial-specialization11.C 
b/gcc/testsuite/g++.dg/template/partial-specialization11.C
new file mode 100644
index 000..20da407d422
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/partial-specialization11.C
@@ -0,0 +1,10 @@
+// PR c++/105289
+
+template struct value_type;
+
+template::type V>
+struct push_front_vlist;
+
+template
+struct push_front_vlist { };
+// { dg-error "not more specialized" "PR86193" { target c++14_down } .-1 }
diff --git a/gcc/testsuite/g++.dg/template/partial-specialization12.C 
b/gcc/testsuite/g++.dg/template/partial-specialization12.C
new file mode 100644
index 000..d70f7592790
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/partial-specialization12.C
@@ -0,0 +1,12 @@
+// PR c++/105289
+// { dg-do compile { target c++11 } }
+
+template
+struct value_type;
+
+template ::type Element>
+struct push_front_vlist;
+
+template  class XList, class T, T Arg, T... Vs>
+struct push_front_vlist, Arg> { };
+// { dg-error "not more specialized" "PR86193" { target c++14_down } .-1 }
diff --git a/gcc/testsuite/g++.dg/template/partial5.C 

[PATCH] c++: partial ordering with dependent NTTP type [PR105289]

2022-04-22 Thread Patrick Palka via Gcc-patches
Here ever since r11-6483-ge2e2f3f2c9400f we're rejecting and crashing
(respectively) on two testcases that we used to accept in C++17 mode.
Both testcases declare partial specializations for which the primary
template contains an NTTP with dependent type, but the correctness of
these partial specializations is unclear according to PR86193.

This patch restores the previous C++17 behavior for such partial
specializations by restricting the r11-6483 change to just ordinary
deduction as opposed to deduction for sake of partial ordering.

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

PR c++/105289
PR c++/86193

gcc/cp/ChangeLog:

* pt.cc (unify) : Restrict the
r11-6483 change to just ordinary deduction for function
templates.  When substituting into the NTTP type the second
time, use the original type not the substituted type.  Remove
now unnecessary level check.

gcc/testsuite/ChangeLog:

* g++.dg/template/partial5.C: Revert r11-6483 change.
* g++.dg/template/partial-specialization11.C: New test.
* g++.dg/template/partial-specialization12.C: New test.
---
 gcc/cp/pt.cc  | 25 ---
 .../template/partial-specialization11.C   | 10 
 .../template/partial-specialization12.C   | 12 +
 gcc/testsuite/g++.dg/template/partial5.C  |  2 +-
 4 files changed, 39 insertions(+), 10 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/partial-specialization11.C
 create mode 100644 gcc/testsuite/g++.dg/template/partial-specialization12.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index dde62ee052d..52bd130b7e7 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -24287,8 +24287,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, 
int strict,
  /* We haven't deduced the type of this parameter yet.  */
  if (cxx_dialect >= cxx17
  /* We deduce from array bounds in try_array_deduction.  */
- && !(strict & UNIFY_ALLOW_INTEGER)
- && TEMPLATE_PARM_LEVEL (parm) <= TMPL_ARGS_DEPTH (targs))
+ && !(strict & UNIFY_ALLOW_INTEGER))
{
  /* Deduce it from the non-type argument.  As above, ignore
 top-level quals here too.  */
@@ -24296,13 +24295,21 @@ unify (tree tparms, tree targs, tree parm, tree arg, 
int strict,
  RECUR_AND_CHECK_FAILURE (tparms, targs,
   tparm, atype,
   UNIFY_ALLOW_NONE, explain_p);
- /* Now check whether the type of this parameter is still
-dependent, and give up if so.  */
- ++processing_template_decl;
- tparm = tsubst (tparm, targs, tf_none, NULL_TREE);
- --processing_template_decl;
- if (uses_template_parms (tparm))
-   return unify_success (explain_p);
+ if (!processing_template_decl
+ && TPARMS_PRIMARY_TEMPLATE (tparms)
+ && DECL_FUNCTION_TEMPLATE_P (TPARMS_PRIMARY_TEMPLATE
+  (tparms)))
+   {
+ /* If the NTTP's type uses still-undeduced template
+parameters, then don't unify it now.  This gives
+type_unification_real a chance to retry deduction
+with default template arguments substituted in.  */
+ ++processing_template_decl;
+ tparm = tsubst (TREE_TYPE (parm), targs, tf_none, NULL_TREE);
+ --processing_template_decl;
+ if (uses_template_parms (tparm))
+   return unify_success (explain_p);
+   }
}
  else
/* Try again later.  */
diff --git a/gcc/testsuite/g++.dg/template/partial-specialization11.C 
b/gcc/testsuite/g++.dg/template/partial-specialization11.C
new file mode 100644
index 000..20da407d422
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/partial-specialization11.C
@@ -0,0 +1,10 @@
+// PR c++/105289
+
+template struct value_type;
+
+template::type V>
+struct push_front_vlist;
+
+template
+struct push_front_vlist { };
+// { dg-error "not more specialized" "PR86193" { target c++14_down } .-1 }
diff --git a/gcc/testsuite/g++.dg/template/partial-specialization12.C 
b/gcc/testsuite/g++.dg/template/partial-specialization12.C
new file mode 100644
index 000..d70f7592790
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/partial-specialization12.C
@@ -0,0 +1,12 @@
+// PR c++/105289
+// { dg-do compile { target c++11 } }
+
+template
+struct value_type;
+
+template ::type Element>
+struct push_front_vlist;
+
+template  class XList, class T, T Arg, T... Vs>
+struct push_front_vlist, Arg> { };
+// { dg-error "not more specialized" "PR86193" { target c++14_down } .-1 }
diff --git a/gcc/testsuite/g++.dg/template/partial5.C 

[PATCH] libstdc++: Avoid ASCII assumptions in floating_from_chars.cc

2022-04-21 Thread Patrick Palka via Gcc-patches
In starts_with_ci and in __floating_from_chars_hex's inf/nan handling,
we were assuming that the letters are contiguous and that 'A' + 32 == 'a'
which is true for ASCII but not for other character encodings.  This
patch fixes starts_with_ci by using a constexpr lookup table that maps
uppercase letters to lowercase, and fixes __floating_from_chars_hex by
using __from_chars_alnum_to_val.

Tested on x86_64-pc-linux-gnu, does this look OK for trunk?

libstdc++-v3/ChangeLog:

* include/std/charconv (__from_chars_alnum_to_val_table):
Simplify initialization of __lower/__upper_letters.
(__from_chars_alnum_to_val): Default the template parameter to
false.
* src/c++17/floating_from_chars.cc (starts_with_ci): Don't
assume the uppercase and lowercase letters are contiguous.
(__floating_from_chars_hex): Likewise.
---
 libstdc++-v3/include/std/charconv | 12 ++-
 libstdc++-v3/src/c++17/floating_from_chars.cc | 33 ++-
 2 files changed, 28 insertions(+), 17 deletions(-)

diff --git a/libstdc++-v3/include/std/charconv 
b/libstdc++-v3/include/std/charconv
index 561234cb2fc..218813e4797 100644
--- a/libstdc++-v3/include/std/charconv
+++ b/libstdc++-v3/include/std/charconv
@@ -412,14 +412,8 @@ namespace __detail
   constexpr auto
   __from_chars_alnum_to_val_table()
   {
-constexpr unsigned char __lower_letters[]
-  = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
- 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
- 'u', 'v', 'w', 'x', 'y', 'z' };
-constexpr unsigned char __upper_letters[]
-  = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
- 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
- 'U', 'V', 'W', 'X', 'Y', 'Z' };
+constexpr unsigned char __lower_letters[27] = "abcdefghijklmnopqrstuvwxyz";
+constexpr unsigned char __upper_letters[27] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
 struct { unsigned char __data[1u << __CHAR_BIT__] = {}; } __table;
 for (auto& __entry : __table.__data)
   __entry = 127;
@@ -437,7 +431,7 @@ namespace __detail
   // return its corresponding base-10 value, otherwise return a value >= 127.
   // If _DecOnly is false: if the character is an alphanumeric digit, then
   // return its corresponding base-36 value, otherwise return a value >= 127.
-  template
+  template
 unsigned char
 __from_chars_alnum_to_val(unsigned char __c)
 {
diff --git a/libstdc++-v3/src/c++17/floating_from_chars.cc 
b/libstdc++-v3/src/c++17/floating_from_chars.cc
index 0f5183aa9b5..71fb8c5c9a3 100644
--- a/libstdc++-v3/src/c++17/floating_from_chars.cc
+++ b/libstdc++-v3/src/c++17/floating_from_chars.cc
@@ -30,6 +30,7 @@
 // Prefer to use std::pmr::string if possible, which requires the cxx11 ABI.
 #define _GLIBCXX_USE_CXX11_ABI 1
 
+#include 
 #include 
 #include 
 #include 
@@ -451,15 +452,33 @@ namespace
 
 #if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64
   // Return true iff [FIRST,LAST) begins with PREFIX, ignoring case.
+  // PREFIX is assumed to not contain any uppercase letters.
   bool
   starts_with_ci(const char* first, const char* last, string_view prefix)
   {
 __glibcxx_requires_valid_range(first, last);
 
-for (char ch : prefix)
+// A lookup table that maps uppercase letters to lowercase and
+// is otherwise the identity mapping.
+static constexpr auto upper_to_lower_table = [] {
+  constexpr unsigned char lower_letters[27] = "abcdefghijklmnopqrstuvwxyz";
+  constexpr unsigned char upper_letters[27] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  std::array table = {};
+  for (unsigned i = 0; i < table.size(); ++i)
+   table[i] = i;
+  for (unsigned i = 0; i < 26; ++i)
+   table[upper_letters[i]] = lower_letters[i];
+  return table;
+}();
+
+if (last - first < static_cast(prefix.length()))
+  return false;
+
+for (const unsigned char pch : prefix)
   {
-   __glibcxx_assert(ch >= 'a' && ch <= 'z');
-   if (first == last || (*first != ch && *first != ch - 32))
+   __glibcxx_assert(pch == upper_to_lower_table[pch]);
+   const unsigned char ch = *first;
+   if (ch != pch && upper_to_lower_table[ch] != pch)
  return false;
++first;
   }
@@ -535,10 +554,8 @@ namespace
  ++first;
  break;
}
- else if ((ch >= '0' && ch <= '9')
-  || (ch >= 'a' && ch <= 'z')
-  || (ch >= 'A' && ch <= 'Z')
-  || ch == '_')
+ else if (ch == '_'
+  || __detail::__from_chars_alnum_to_val(ch) < 127)
continue;
  else
{
@@ -599,7 +616,7 @@ namespace
continue;
  }
 
-   int hexit = __detail::__from_chars_alnum_to_val(ch);
+   int hexit = 

[PATCH] libstdc++: Work around modules ICE in [PR105297]

2022-04-20 Thread Patrick Palka via Gcc-patches
This makes the initializer for __table in __from_chars_alnum_to_val
dependent in an artificial way, which works around the modules testsuite
ICE reported in PR105297 by preventing the initializer from getting
evaluated at parse time.

Compared to the alternative workaround of using a non-local class type
for __table, this workaround has the advantage of slightly speeding up
compilation of the  header, since now the table will not get
built (via constexpr evaluation) until one of the integer std::from_chars
overloads is actually instantiated.

Tested on x86_64-pc-linux-gnu, does this look OK for trunk?

PR c++/105297
PR c++/105322

libstdc++-v3/ChangeLog:

* include/std/charconv (__from_chars_alnum_to_val): Make
initializer for __table dependent in an artificial way.
---
 libstdc++-v3/include/std/charconv | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/charconv 
b/libstdc++-v3/include/std/charconv
index f1ace406017..561234cb2fc 100644
--- a/libstdc++-v3/include/std/charconv
+++ b/libstdc++-v3/include/std/charconv
@@ -445,7 +445,9 @@ namespace __detail
return __c - '0';
   else
{
- static constexpr auto __table = __from_chars_alnum_to_val_table();
+ // This initializer is deliberately made dependent in order to work
+ // around modules bug PR105322.
+ static constexpr auto __table = (_DecOnly, 
__from_chars_alnum_to_val_table());
  return __table.__data[__c];
}
 }
-- 
2.36.0.rc2.10.g1ac7422e39



[PATCH] libstdc++: Micro-optimize __from_chars_pow2_base

2022-04-18 Thread Patrick Palka via Gcc-patches
At the first iteration of __from_chars_pow2_base's main loop, we need
to remember the value of the leading significant digit for sake of the
overflow check at the end of the function (for bases other than 2).

This patch manually unrolls this first iteration so as to not encumber
the entire loop with logic that only the first iteration needs.  This
seems to significantly improve performance:

Base  Before  After (seconds, lower is better)
   29.36   9.37
   83.66   2.93
  162.93   1.91
  322.39   2.24

Tested on x86_64-pc-linux-gnu, does this look OK for trunk?

libstdc++-v3/ChangeLog:

* include/std/charconv (__from_chars_pow2_base): Manually
unroll the first iteration of the main loop and simplify
accordingly.
---
 libstdc++-v3/include/std/charconv | 30 +-
 1 file changed, 21 insertions(+), 9 deletions(-)

diff --git a/libstdc++-v3/include/std/charconv 
b/libstdc++-v3/include/std/charconv
index dda4ec87779..cd7f52e2195 100644
--- a/libstdc++-v3/include/std/charconv
+++ b/libstdc++-v3/include/std/charconv
@@ -469,25 +469,37 @@ namespace __detail
   while (__i < __len && __first[__i] == '0')
++__i;
   const ptrdiff_t __leading_zeroes = __i;
+  if (__i >= __len) [[__unlikely__]]
+   {
+ __first += __i;
+ return true;
+   }
+
+  // Remember the leading significant digit value if necessary.
+  unsigned char __leading_c;
+  if (__base != 2)
+   {
+ __leading_c = __from_chars_alnum_to_val<_DecOnly>(__first[__i]);
+ // __glibcxx_assert(__leading_c != 0);
+ if (__leading_c >= __base) [[__unlikely__]]
+   {
+ __first += __i;
+ return true;
+   }
+ __val = __leading_c;
+ ++__i;
+   }
 
-  unsigned char __leading_c = 0;
   for (; __i < __len; ++__i)
{
  const unsigned char __c = 
__from_chars_alnum_to_val<_DecOnly>(__first[__i]);
  if (__c >= __base)
break;
  __val = (__val << __log2_base) | __c;
-
- if (__i == __leading_zeroes)
-   {
- // At the first iteration, remember the leading significant digit.
- // __glibcxx_assert(__leading_c == 0 && __c != 0);
- __leading_c = __c;
-   }
}
   __first += __i;
   auto __significant_bits = (__i - __leading_zeroes) * __log2_base;
-  if (__base != 2 && __leading_c != 0)
+  if (__base != 2)
// Compensate for a leading significant digit that didn't use all
// of its available bits.
__significant_bits -= __log2_base - __bit_width(__leading_c);
-- 
2.36.0.rc2.10.g1ac7422e39



Re: [PATCH] c++: Fix up CONSTRUCTOR_PLACEHOLDER_BOUNDARY handling [PR105256]

2022-04-18 Thread Patrick Palka via Gcc-patches
On Sun, Apr 17, 2022 at 6:24 PM Jason Merrill  wrote:
>
> On 4/15/22 07:22, Jakub Jelinek wrote:
> > Hi!
> >
> > The CONSTRUCTOR_PLACEHOLDER_BOUNDARY bit is supposed to separate
> > PLACEHOLDER_EXPRs that should be replaced by one object or subobjects of it
> > (variable, TARGET_EXPR slot, ...) from other PLACEHOLDER_EXPRs that should
> > be replaced by different objects or subobjects.
> > The bit is set when finding PLACEHOLDER_EXPRs inside of a CONSTRUCTOR, not
> > looking into nested CONSTRUCTOR_PLACEHOLDER_BOUNDARY ctors, and we prevent
> > elision of TARGET_EXPRs (through TARGET_EXPR_NO_ELIDE) whose initializer
> > is a CONSTRUCTOR_PLACEHOLDER_BOUNDARY ctor.  The following testcase ICEs
> > though, we don't replace the placeholders in there at all, because
> > CONSTRUCTOR_PLACEHOLDER_BOUNDARY isn't set on the TARGET_EXPR_INITIAL
> > ctor, but on a ctor nested in such a ctor.  replace_placeholders should be
> > run on the whole TARGET_EXPR slot.
> >
> > So, the following patch fixes it by moving the 
> > CONSTRUCTOR_PLACEHOLDER_BOUNDARY
> > bit from nested CONSTRUCTORs to the CONSTRUCTOR containing those (but only
> > if it is closely nested, if there is some other tree sandwiched in between,
> > it doesn't do it).
>
> Hmm, Patrick made a similar change and then reverted it for PR90996.
> But it makes sense to me; when we replace placeholders, it's appropriate
> to look at the whole aggregate initialization rather than the innermost
> CONSTRUCTOR that has DMIs.  Patrick, was there a reason that change
> seemed wrong to you, or was it just unnecessary for the bug you were
> working on?

That change was just not strictly necessary for PR90996 I think.  For
that testcase:

struct S {
  int & = 2;
  int b[1] {a};
};

S c[] {{2}};

we first call replace_placeholders from store_init_value for the
overall initiializer for c

  {{.a=(int &) &_ZGR1c_, .b={*(&)->a}}

but CONSTRUCTOR_PLACEHOLDER_BOUNDARY set on the middle pair of {}
prevents the placeholder from being resolved to c[0].  The reverted
change would have allowed us to resolve the placeholder at this point,
since the flag would have been moved to the outermost {} IIUC.

But fortunately split_nonconstant_init then factors out the
initialization of c[0].b into an INIT_EXPR:

  c[0].b[0] = *(&)->a;

during gimplification of which we attempt replace_placeholders again
which succeeds this time at resolving the placeholder, due to the
other change in r10-7587 that made replace_placeholders look through
all handled components, not just COMPONENT_REF (mirroring
replace_placeholders_r).

So I reverted the rest of r10-7587 after Martin noticed it had no
effect: https://gcc.gnu.org/pipermail/gcc-patches/2020-April/543918.html

The reverted change and Jakub's more general patch seem right/safe to
me FWIW, I just couldn't come up with a testcase that demonstrated its
need at the time unfortunately.



>
> > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
> >
> > 2022-04-15  Jakub Jelinek  
> >
> >   PR c++/105256
> >   * typeck2.cc (process_init_constructor_array,
> >   process_init_constructor_record, process_init_constructor_union): Move
> >   CONSTRUCTOR_PLACEHOLDER_BOUNDARY flag from CONSTRUCTOR elements to the
> >   containing CONSTRUCTOR.
> >
> >   * g++.dg/cpp0x/pr105256.C: New test.
> >
> > --- gcc/cp/typeck2.cc.jj  2022-04-07 09:09:54.432995137 +0200
> > +++ gcc/cp/typeck2.cc 2022-04-14 16:02:12.438432494 +0200
> > @@ -1515,6 +1515,14 @@ process_init_constructor_array (tree typ
> > strip_array_types (TREE_TYPE (ce->value);
> >
> > picflags |= picflag_from_initializer (ce->value);
> > +  /* Propagate CONSTRUCTOR_PLACEHOLDER_BOUNDARY to outer
> > +  CONSTRUCTOR.  */
> > +  if (TREE_CODE (ce->value) == CONSTRUCTOR
> > +   && CONSTRUCTOR_PLACEHOLDER_BOUNDARY (ce->value))
> > + {
> > +   CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init) = 1;
> > +   CONSTRUCTOR_PLACEHOLDER_BOUNDARY (ce->value) = 0;
> > + }
> >   }
> >
> > /* No more initializers. If the array is unbounded, we are done. 
> > Otherwise,
> > @@ -1560,6 +1568,14 @@ process_init_constructor_array (tree typ
> > }
> >
> >   picflags |= picflag_from_initializer (next);
> > + /* Propagate CONSTRUCTOR_PLACEHOLDER_BOUNDARY to outer
> > +CONSTRUCTOR.  */
> > + if (TREE_CODE (next) == CONSTRUCTOR
> > + && CONSTRUCTOR_PLACEHOLDER_BOUNDARY (next))
> > +   {
> > + CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init) = 1;
> > + CONSTRUCTOR_PLACEHOLDER_BOUNDARY (next) = 0;
> > +   }
> >   if (len > i+1)
> > {
> >   tree range = build2 (RANGE_EXPR, size_type_node,
> > @@ -1754,6 +1770,13 @@ process_init_constructor_record (tree ty
> > if (fldtype != TREE_TYPE (field))
> >   next = cp_convert_and_check (TREE_TYPE (field), next, complain);
> > picflags |= 

Re: [PATCH] libstdc++: Avoid double-deref of __first in ranges::minmax [PR104858]

2022-04-15 Thread Patrick Palka via Gcc-patches
On Thu, 14 Apr 2022, Jonathan Wakely wrote:

> On Thu, 14 Apr 2022 at 16:21, Patrick Palka via Libstdc++
>  wrote:
> >
> > Tested on x86_64-pc-linux-gnu, does this look OK for trunk and 11/10
> > once the branch is unfrozen?
> >
> > PR libstdc++/104858
> >
> > libstdc++-v3/ChangeLog:
> >
> > * include/bits/ranges_algo.h (__minmax_fn): Avoid dereferencing
> > __first twice at the start.
> > * testsuite/25_algorithms/minmax/constrained.cc (test06): New test.
> > ---
> >  libstdc++-v3/include/bits/ranges_algo.h   |  2 +-
> >  .../25_algorithms/minmax/constrained.cc   | 23 +++
> >  2 files changed, 24 insertions(+), 1 deletion(-)
> >
> > diff --git a/libstdc++-v3/include/bits/ranges_algo.h 
> > b/libstdc++-v3/include/bits/ranges_algo.h
> > index 62dc605080a..3d30fb1428c 100644
> > --- a/libstdc++-v3/include/bits/ranges_algo.h
> > +++ b/libstdc++-v3/include/bits/ranges_algo.h
> > @@ -3084,7 +3084,7 @@ namespace ranges
> > auto __last = ranges::end(__r);
> > __glibcxx_assert(__first != __last);
> > auto __comp_proj = __detail::__make_comp_proj(__comp, __proj);
> > -   minmax_result> __result = {*__first, 
> > *__first};
> > +   minmax_result> __result = {*__first, 
> > __result.min};
> 
> Clever ... I'm surprised this even works. I would have expected it to
> evaluate both initializers before actually initializing the members.
> TIL.

Indeed, it seems to do the right thing, practically speaking at least :)
FWIW the alternative approach

-   minmax_result> __result = {*__first, *__first};
+   minmax_result> __result;
+   __result.max = __result.min = *__first;

wouldn't be right because the value type is not necessarily default
constructible.  I beefed up the new testcase to verify we don't demand
default constructibility here.



[PATCH] libstdc++: Stop defining _GLIBCXX_ASSERTIONS in floating_to_chars.cc

2022-04-14 Thread Patrick Palka via Gcc-patches
Assertions were originally enabled in the compiled-in floating-point
std::to_chars implementation to help shake out any bugs, but they
apparently impose a significant performance penalty, in particular for
the hex formatting which is around 25% slower with assertions enabled.
This seems too high of a cost for unconditionally enabling them.

The newly added calls to __builtin_unreachable work around the compiler
no longer knowing that the set of valid values of 'fmt' is limited (which
was previously upheld by an assert).

Tested on x86_64-pc-linux-gnu, does this look OK for trunk?

libstdc++-v3/ChangeLog:

* src/c++17/floating_to_chars.cc: Don't define
_GLIBCXX_ASSERTIONS.
(__floating_to_chars_shortest): Add __builtin_unreachable calls to
squelch false-positive -Wmaybe-uninitialized and -Wreturn-type
warnings.
(__floating_to_chars_precision): Likewise.
---
 libstdc++-v3/src/c++17/floating_to_chars.cc | 9 ++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/libstdc++-v3/src/c++17/floating_to_chars.cc 
b/libstdc++-v3/src/c++17/floating_to_chars.cc
index 66bd457cbe2..4599d68a39c 100644
--- a/libstdc++-v3/src/c++17/floating_to_chars.cc
+++ b/libstdc++-v3/src/c++17/floating_to_chars.cc
@@ -22,9 +22,6 @@
 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 // .
 
-// Activate __glibcxx_assert within this file to shake out any bugs.
-#define _GLIBCXX_ASSERTIONS 1
-
 #include 
 
 #include 
@@ -1114,6 +,7 @@ template
   }
 
 __glibcxx_assert(false);
+__builtin_unreachable();
   }
 
 template
@@ -1202,6 +1200,8 @@ template
effective_precision = min(precision, max_eff_scientific_precision);
output_specifier = "%.*Lg";
  }
+   else
+ __builtin_unreachable();
const int excess_precision = (fmt != chars_format::general
  ? precision - effective_precision : 0);
 
@@ -1234,6 +1234,8 @@ template
  output_length_upper_bound = sign + strlen("0");
output_length_upper_bound += sizeof(radix) + effective_precision;
  }
+   else
+ __builtin_unreachable();
 
// Do the sprintf into the local buffer.
char buffer[output_length_upper_bound+1];
@@ -1570,6 +1572,7 @@ template
   }
 
 __glibcxx_assert(false);
+__builtin_unreachable();
   }
 
 // Define the overloads for float.
-- 
2.36.0.rc2.10.g1ac7422e39



Re: [PATCH] libstdc++: Optimize std::has_single_bit

2022-04-14 Thread Patrick Palka via Gcc-patches
On Thu, Apr 14, 2022 at 2:59 PM Jonathan Wakely  wrote:
>
> On Thu, 14 Apr 2022 at 19:17, Patrick Palka via Libstdc++
>  wrote:
> >
> > This reimplements std::has_single_bit using the well-known bit-twiddilng
> > trick[1], which is much faster than popcount on x86_64.
>
> Is that always true for all microarchitectures? We have
> https://gcc.gnu.org/PR97759 on this topic, and I think we agreed that
> the compiler should match the popcount pattern and Do The Right Thing
> for the target and current -march.

Whoops, I completely forgot that we had a PR about this!  Makes sense
to fix this on the compiler side instead.

>
> If we're confident it's always better, that PR number should go in the
> changelog.
>
> > Note that when __x is signed and maximally negative then this
> > implementation invokes UB due to signed overflow, whereas the previous
> > implementation would return true.  This isn't a problem for
> > has_single_bit because it accepts only unsigned types, but it is a
> > potential problem for the unconstrained __has_single_bit.  Should
> > __has_single_bit continue to handle this non-standard case correctly for
> > sake of backwards compatibility?
>
> No. The extensions have the same preconditions as the corresponding
> standard functions, we just don't check them. The code using them is
> internal to the library and should only use unsigned types. Users
> relying on the extensions need to meet those preconditions too.

Understood, thanks!

>
> > Tested on x86_64-pc-linux-gnu.
> >
> > [1]: 
> > http://www.graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2
> >
> > libstdc++-v3/ChangeLog:
> >
> > * include/std/bit (__has_single_bit): Define in terms of
> > bitwise-and, not popcount.
> > ---
> >  libstdc++-v3/include/std/bit | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/libstdc++-v3/include/std/bit b/libstdc++-v3/include/std/bit
> > index ef19d649e32..621ee4a9b95 100644
> > --- a/libstdc++-v3/include/std/bit
> > +++ b/libstdc++-v3/include/std/bit
> > @@ -316,7 +316,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> >template
> >  constexpr bool
> >  __has_single_bit(_Tp __x) noexcept
> > -{ return std::__popcount(__x) == 1; }
> > +{ return __x != 0 && (__x & (__x - 1)) == 0; }
> >
> >template
> >  constexpr _Tp
> > --
> > 2.36.0.rc2.10.g1ac7422e39
> >
>



[PATCH] libstdc++: Optimize std::has_single_bit

2022-04-14 Thread Patrick Palka via Gcc-patches
This reimplements std::has_single_bit using the well-known bit-twiddilng
trick[1], which is much faster than popcount on x86_64.

Note that when __x is signed and maximally negative then this
implementation invokes UB due to signed overflow, whereas the previous
implementation would return true.  This isn't a problem for
has_single_bit because it accepts only unsigned types, but it is a
potential problem for the unconstrained __has_single_bit.  Should
__has_single_bit continue to handle this non-standard case correctly for
sake of backwards compatibility?

Tested on x86_64-pc-linux-gnu.

[1]: http://www.graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2

libstdc++-v3/ChangeLog:

* include/std/bit (__has_single_bit): Define in terms of
bitwise-and, not popcount.
---
 libstdc++-v3/include/std/bit | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/bit b/libstdc++-v3/include/std/bit
index ef19d649e32..621ee4a9b95 100644
--- a/libstdc++-v3/include/std/bit
+++ b/libstdc++-v3/include/std/bit
@@ -316,7 +316,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template
 constexpr bool
 __has_single_bit(_Tp __x) noexcept
-{ return std::__popcount(__x) == 1; }
+{ return __x != 0 && (__x & (__x - 1)) == 0; }
 
   template
 constexpr _Tp
-- 
2.36.0.rc2.10.g1ac7422e39



[PATCH] libstdc++: Avoid double-deref of __first in ranges::minmax [PR104858]

2022-04-14 Thread Patrick Palka via Gcc-patches
Tested on x86_64-pc-linux-gnu, does this look OK for trunk and 11/10
once the branch is unfrozen?

PR libstdc++/104858

libstdc++-v3/ChangeLog:

* include/bits/ranges_algo.h (__minmax_fn): Avoid dereferencing
__first twice at the start.
* testsuite/25_algorithms/minmax/constrained.cc (test06): New test.
---
 libstdc++-v3/include/bits/ranges_algo.h   |  2 +-
 .../25_algorithms/minmax/constrained.cc   | 23 +++
 2 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/bits/ranges_algo.h 
b/libstdc++-v3/include/bits/ranges_algo.h
index 62dc605080a..3d30fb1428c 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -3084,7 +3084,7 @@ namespace ranges
auto __last = ranges::end(__r);
__glibcxx_assert(__first != __last);
auto __comp_proj = __detail::__make_comp_proj(__comp, __proj);
-   minmax_result> __result = {*__first, *__first};
+   minmax_result> __result = {*__first, 
__result.min};
if (++__first == __last)
  return __result;
else
diff --git a/libstdc++-v3/testsuite/25_algorithms/minmax/constrained.cc 
b/libstdc++-v3/testsuite/25_algorithms/minmax/constrained.cc
index 90882afb6d0..306c495babe 100644
--- a/libstdc++-v3/testsuite/25_algorithms/minmax/constrained.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/minmax/constrained.cc
@@ -129,6 +129,28 @@ test05()
   VERIFY( result.min == "a"s && result.max == "c"s );
 }
 
+struct A {
+  A() = default;
+  A(const A&) = default;
+  A(A&&) { ++move_count; }
+  A& operator=(const A&) = default;
+  A& operator=(A&&) = default;
+  friend auto operator<=>(const A&, const A&) = default;
+  static inline int move_count = 0;
+};
+
+void
+test06()
+{
+  // PR libstdc++/104858
+  // Verify ranges::minmax doesn't dereference the iterator for the first
+  // element in the range twice.
+  A a;
+  ranges::subrange r = {std::move_iterator(), std::move_sentinel( + 1)};
+  ranges::minmax(r);
+  VERIFY( A::move_count == 1 );
+}
+
 int
 main()
 {
@@ -137,4 +159,5 @@ main()
   test03();
   test04();
   test05();
+  test06();
 }
-- 
2.36.0.rc2.10.g1ac7422e39



Re: [PATCH] libstdc++: Optimize integer std::from_chars

2022-04-14 Thread Patrick Palka via Gcc-patches
On Thu, 14 Apr 2022, Patrick Palka wrote:

> This applies the following optimizations to the integer std::from_chars
> implementation:
> 
>   1. Use a lookup table for converting an alphanumeric digit to its
>  base-36 value instead of using a range test (for 0-9) and switch
>  (for a-z and A-Z).  The table is constructed using a C++14
>  constexpr function which doesn't assume a particular character
>  encoding or __CHAR_BIT__ value.  The new conversion function
>  __from_chars_alnum_to_val is templated on whether we care
>  only about the decimal digits, in which case we can perform the
>  conversion with a single subtraction since the digit characters
>  are guaranteed to be contiguous (unlike the letters).
>   2. Generalize __from_chars_binary to handle all power-of-two bases.
>  This function, now named __from_chars_pow2_base, is also templated
>  on whether we care only about the decimal digits in order to speed
>  up digit conversion for base 2, 4 and 8.
>   3. In __from_chars_digit, use
>static_cast(__c - '0') < __base
>  instead of
>'0' <= __c && __c <= ('0' + (__base - 1)).
>  as the digit recognition test (exhaustively verified that the two
>  tests are equivalent).
>   4. In __from_chars_alnum, use a nested loop to consume the rest of the
>  digits in the overflow case (mirroring __from_chars_digit) so that
>  the main loop doesn't have to maintain the __valid overflow flag.
> 
> At this point, __from_chars_digit is nearly identical to
> __from_chars_alnum, so this patch combines the two functions, removing
> the former and templatizing the latter according to whether we care only
> about the decimal digits.  Finally,
> 
>   5. In __from_chars_alnum, keep track of a lower bound on the number of
>  unused bits in the result and use that to omit the overflow check
>  when it's safe to do so.
> 
> In passing this replaces the non-portable function ascii_to_hexit
> used by __floating_from_chars_hex with the new conversion function.
> 
> Here are some runtime measurements for a simple 15-line benchmark that
> roundtrips printing/parsing 200 million integers via std::to/from_chars
> (average of 5 runs):
> 
>   Base  Before  After (seconds, lower is better)
>  29.37   9.37
>  3   12.13  15.79
>  83.67   4.15
> 103.86   4.90
> 115.03   6.84
> 162.93   4.14
> 322.39   3.85
> 363.26   5.22

Whoops, the second and third columns should be swapped (runtime is
smaller after the patch across the board).

> 
> Testedon x86_64-pc-linux-gnu, does this look OK for trunk?  Also tested
> against libc++'s from_chars tests for good measure.
> 
> libstdc++-v3/ChangeLog:
> 
>   * include/std/charconv (__from_chars_alnum_to_val_table): Define.
>   (__from_chars_alnum_to_val): Define.
>   (__from_chars_binary): Rename to ...
>   (__from_chars_pow2_base): ... this.  Generalize to handle any
>   power-of-two base using __from_chars_alnum_to_val.
>   (__from_chars_digit): Optimize digit recognition to a single
>   test instead of two tests.  Use [[__unlikely___]] attribute.
>   (__from_chars_alpha_to_num): Remove.
>   (__from_chars_alnum): Use __from_chars_alnum_to_val.  Use a
>   nested loop for the overflow case.
>   (from_chars): Adjust appropriately.
>   * src/c++17/floating_from_chars.cc (ascii_to_hexit): Remove.
>   (__floating_from_chars_hex): Use __from_chars_alnum_to_val
>   to recognize a hex digit instead.
> ---
>  libstdc++-v3/include/std/charconv | 250 --
>  libstdc++-v3/src/c++17/floating_from_chars.cc |  18 +-
>  2 files changed, 105 insertions(+), 163 deletions(-)
> 
> diff --git a/libstdc++-v3/include/std/charconv 
> b/libstdc++-v3/include/std/charconv
> index 2ce9c7d4cb9..5e44459749a 100644
> --- a/libstdc++-v3/include/std/charconv
> +++ b/libstdc++-v3/include/std/charconv
> @@ -407,176 +407,127 @@ namespace __detail
>return true;
>  }
>  
> -  /// std::from_chars implementation for integers in base 2.
> -  template
> +  // Construct and return a lookup table that maps 0-9, A-Z and a-z to the
> +  // corresponding corresponding base-36 value and maps all other characters
> +  // to 127.
> +  constexpr auto
> +  __from_chars_alnum_to_val_table()
> +  {
> +constexpr unsigned char __lower_letters[]
> +  = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
> +   'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
> +   'u', 'v', 'w', 'x', 'y', 'z' };
> +constexpr unsigned char __upper_letters[]
> +  = { 'A', 'B', 'C', 'D', 

[PATCH] libstdc++: Optimize integer std::from_chars

2022-04-14 Thread Patrick Palka via Gcc-patches
This applies the following optimizations to the integer std::from_chars
implementation:

  1. Use a lookup table for converting an alphanumeric digit to its
 base-36 value instead of using a range test (for 0-9) and switch
 (for a-z and A-Z).  The table is constructed using a C++14
 constexpr function which doesn't assume a particular character
 encoding or __CHAR_BIT__ value.  The new conversion function
 __from_chars_alnum_to_val is templated on whether we care
 only about the decimal digits, in which case we can perform the
 conversion with a single subtraction since the digit characters
 are guaranteed to be contiguous (unlike the letters).
  2. Generalize __from_chars_binary to handle all power-of-two bases.
 This function, now named __from_chars_pow2_base, is also templated
 on whether we care only about the decimal digits in order to speed
 up digit conversion for base 2, 4 and 8.
  3. In __from_chars_digit, use
   static_cast(__c - '0') < __base
 instead of
   '0' <= __c && __c <= ('0' + (__base - 1)).
 as the digit recognition test (exhaustively verified that the two
 tests are equivalent).
  4. In __from_chars_alnum, use a nested loop to consume the rest of the
 digits in the overflow case (mirroring __from_chars_digit) so that
 the main loop doesn't have to maintain the __valid overflow flag.

At this point, __from_chars_digit is nearly identical to
__from_chars_alnum, so this patch combines the two functions, removing
the former and templatizing the latter according to whether we care only
about the decimal digits.  Finally,

  5. In __from_chars_alnum, keep track of a lower bound on the number of
 unused bits in the result and use that to omit the overflow check
 when it's safe to do so.

In passing this replaces the non-portable function ascii_to_hexit
used by __floating_from_chars_hex with the new conversion function.

Here are some runtime measurements for a simple 15-line benchmark that
roundtrips printing/parsing 200 million integers via std::to/from_chars
(average of 5 runs):

  Base  Before  After (seconds, lower is better)
 29.37   9.37
 3   12.13  15.79
 83.67   4.15
103.86   4.90
115.03   6.84
162.93   4.14
322.39   3.85
363.26   5.22

Testedon x86_64-pc-linux-gnu, does this look OK for trunk?  Also tested
against libc++'s from_chars tests for good measure.

libstdc++-v3/ChangeLog:

* include/std/charconv (__from_chars_alnum_to_val_table): Define.
(__from_chars_alnum_to_val): Define.
(__from_chars_binary): Rename to ...
(__from_chars_pow2_base): ... this.  Generalize to handle any
power-of-two base using __from_chars_alnum_to_val.
(__from_chars_digit): Optimize digit recognition to a single
test instead of two tests.  Use [[__unlikely___]] attribute.
(__from_chars_alpha_to_num): Remove.
(__from_chars_alnum): Use __from_chars_alnum_to_val.  Use a
nested loop for the overflow case.
(from_chars): Adjust appropriately.
* src/c++17/floating_from_chars.cc (ascii_to_hexit): Remove.
(__floating_from_chars_hex): Use __from_chars_alnum_to_val
to recognize a hex digit instead.
---
 libstdc++-v3/include/std/charconv | 250 --
 libstdc++-v3/src/c++17/floating_from_chars.cc |  18 +-
 2 files changed, 105 insertions(+), 163 deletions(-)

diff --git a/libstdc++-v3/include/std/charconv 
b/libstdc++-v3/include/std/charconv
index 2ce9c7d4cb9..5e44459749a 100644
--- a/libstdc++-v3/include/std/charconv
+++ b/libstdc++-v3/include/std/charconv
@@ -407,176 +407,127 @@ namespace __detail
   return true;
 }
 
-  /// std::from_chars implementation for integers in base 2.
-  template
+  // Construct and return a lookup table that maps 0-9, A-Z and a-z to the
+  // corresponding corresponding base-36 value and maps all other characters
+  // to 127.
+  constexpr auto
+  __from_chars_alnum_to_val_table()
+  {
+constexpr unsigned char __lower_letters[]
+  = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
+ 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
+ 'u', 'v', 'w', 'x', 'y', 'z' };
+constexpr unsigned char __upper_letters[]
+  = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
+ 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
+ 'U', 'V', 'W', 'X', 'Y', 'Z' };
+struct { unsigned char __data[1u << __CHAR_BIT__] = {}; } __table;
+for (auto& __entry : __table.__data)
+  __entry = 127;
+for (int __i = 0; __i < 10; ++__i)
+  __table.__data['0' + __i] = __i;
+for (int __i = 0; __i < 26; ++__i)
+  {
+   __table.__data[__lower_letters[__i]] = 10 + __i;
+   __table.__data[__upper_letters[__i]] = 10 + __i;
+  }
+return __table;
+  }
+
+  /// If _DecOnly is true: if the character is a decimal digit, then
+  /// return its corresponding 

Re: [PATCH] c++: NON_DEPENDENT_EXPR is not potentially constant [PR104507]

2022-04-12 Thread Patrick Palka via Gcc-patches
On Wed, Feb 16, 2022 at 2:47 PM Patrick Palka  wrote:
>
> On Tue, 15 Feb 2022, Jason Merrill wrote:
>
> > On 2/15/22 17:00, Patrick Palka wrote:
> > > On Tue, 15 Feb 2022, Jason Merrill wrote:
> > >
> > > > On 2/15/22 15:13, Patrick Palka wrote:
> > > > > On Tue, 15 Feb 2022, Patrick Palka wrote:
> > > > >
> > > > > > Here we're crashing from potential_constant_expression because it
> > > > > > tries
> > > > > > to perform trial evaluation of the first operand '(bool)__r' of the
> > > > > > conjunction (which is overall wrapped in a NON_DEPENDENT_EXPR), but
> > > > > > cxx_eval_constant_expression ICEs on unhandled trees (of which
> > > > > > CAST_EXPR
> > > > > > is one).
> > > > > >
> > > > > > Since cxx_eval_constant_expression always treats NON_DEPENDENT_EXPR
> > > > > > as non-constant, and since NON_DEPENDENT_EXPR is also opaque to
> > > > > > instantiate_non_dependent_expr, it seems futile to have p_c_e_1 ever
> > > > > > return true for NON_DEPENDENT_EXPR, so let's just instead return 
> > > > > > false
> > > > > > and avoid recursing.
> > > >
> > > > Well, in a template we use pce1 to decide whether to complain about
> > > > something
> > > > that needs to be constant but can't be.  We aren't trying to get a value
> > > > yet.
> > >
> > > Makes sense.. though for NON_DEPENDENT_EXPR in particular, ISTM this
> > > tree is always used in a context where a constant expression isn't
> > > required, e.g. in the build_x_* functions.
> >
> > Fair enough.  The patch is OK with a comment to that effect.
>
> Thanks, I committed the following as r12-7264:

Would it be OK to backport this now for 11.3, or shall we wait until
after 11.3 is released?  It's been two months, and the only reported
fallout from this patch was PR104620, where we began to fail to
diagnose an invalid consteval call within a template ahead of time
(and it turned out we previously were diagnosing it only by accident).
The patch also fixed PR103443 (non-dependent consteval call
incorrectly rejected).

>
> -- >8 --
>
> Subject: [PATCH] c++: treat NON_DEPENDENT_EXPR as not potentially constant
>  [PR104507]
>
> Here we're crashing from potential_constant_expression because it tries
> to perform trial evaluation of the first operand '(bool)__r' of the
> conjunction (which is overall wrapped in a NON_DEPENDENT_EXPR), but
> cxx_eval_constant_expression ICEs on unsupported trees (of which CAST_EXPR
> is one).  The sequence of events is:
>
>   1. build_non_dependent_expr for the array subscript yields
>  NON_DEPENDENT_EXPR<<<(bool)__r && __s>>> ? 1 : 2
>   2. cp_build_array_ref calls fold_non_dependent_expr on this subscript
>  (after this point, processing_template_decl is cleared)
>   3. during which, the COND_EXPR case of tsubst_copy_and_build calls
>  fold_non_dependent_expr on the first operand
>   4. during which, we crash from p_c_e_1 because it attempts trial
>  evaluation of the CAST_EXPR '(bool)__r'.
>
> Note that even if this crash didn't happen, fold_non_dependent_expr
> from cp_build_array_ref would still ultimately be one big no-op here
> since neither constexpr evaluation nor tsubst handle NON_DEPENDENT_EXPR.
>
> In light of this and of the observation that we should never see
> NON_DEPENDENT_EXPR in a context where a constant expression is needed
> (it's used primarily in the build_x_* family of functions), it seems
> futile for p_c_e_1 to ever return true for NON_DEPENDENT_EXPR.  And the
> otherwise inconsistent handling of NON_DEPENDENT_EXPR between p_c_e_1,
> cxx_evaluate_constexpr_expression and tsubst apparently leads to weird
> bugs such as this one.
>
> PR c++/104507
>
> gcc/cp/ChangeLog:
>
> * constexpr.cc (potential_constant_expression_1)
> : Return false instead of recursing.
> Assert tf_error isn't set.
>
> gcc/testsuite/ChangeLog:
>
> * g++.dg/template/non-dependent21.C: New test.
> ---
>  gcc/cp/constexpr.cc | 9 -
>  gcc/testsuite/g++.dg/template/non-dependent21.C | 9 +
>  2 files changed, 17 insertions(+), 1 deletion(-)
>  create mode 100644 gcc/testsuite/g++.dg/template/non-dependent21.C
>
> diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> index 7274c3b760e..4716694cb71 100644
> --- a/gcc/cp/constexpr.cc
> +++ b/gcc/cp/constexpr.cc
> @@ -9065,6 +9065,14 @@ potential_constant_expressio

Re: [PATCH] c++: requires-expr in pack expansion using pack [PR103105]

2022-04-12 Thread Patrick Palka via Gcc-patches
On Tue, Apr 12, 2022 at 12:33 PM Jason Merrill  wrote:
>
> On 4/12/22 12:17, Patrick Palka wrote:
> > Here after dependent substitution of {Ts...} into the alias 'wrap',
> > since we never partially instantiate a requires-expr, we end up with a
> > requires-expr whose REQUIRES_EXPR_EXTRA_ARGS contains an
> > ARGUMENT_PACK_SELECT (which just resolves to the parameter pack Ts).
> > Then when looking up the resulting dependent specialization of A, we
> > crash from iterative_hash_template_arg since it deliberately doesn't
> > handle ARGUMENT_PACK_SELECT.
> >
> > Like with r12-7102-gdb5f1c17031ad8, it seems the right fix here is to
> > resolve ARGUMENT_PACK_SELECT arguments before storing them into an
> > extra args tree (such as REQUIRES_EXPR).
> >
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > trunk/11?  For 11, we'd need to backport r12-7102 as a prereq.
>
> OK, that additional backport seems reasonable.

Thanks a lot, committed to trunk so far.  I attempted backporting this
(along with the mentioned prereq r12-7102) but it seems we also need
to backport your r12-7857-gfc50d9a252c89c (from PR104008) before we
begin to accept the second testcase.  (Now I remember why I sat on
this PR for so long :))

>
>
> >   PR c++/103105
> >   PR c++/103706
> >
> > gcc/cp/ChangeLog:
> >
> >   * pt.cc (build_extra_args): Call preserve_args.
> >
> > gcc/testsuite/ChangeLog:
> >
> >   * g++.dg/cpp2a/concepts-requires29.C: New test.
> >   * g++.dg/cpp2a/concepts-requires29a.C: New test.
> > ---
> >   gcc/cp/pt.cc  |  2 +-
> >   .../g++.dg/cpp2a/concepts-requires29.C| 18 +++
> >   .../g++.dg/cpp2a/concepts-requires29a.C   | 23 +++
> >   3 files changed, 42 insertions(+), 1 deletion(-)
> >   create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-requires29.C
> >   create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-requires29a.C
> >
> > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > index 78519562953..84712e6fc2f 100644
> > --- a/gcc/cp/pt.cc
> > +++ b/gcc/cp/pt.cc
> > @@ -13048,7 +13048,7 @@ build_extra_args (tree pattern, tree args, 
> > tsubst_flags_t complain)
> >   {
> > /* Make a copy of the extra arguments so that they won't get changed
> >out from under us.  */
> > -  tree extra = copy_template_args (args);
> > +  tree extra = preserve_args (copy_template_args (args), /*cow_p=*/false);
> > if (local_specializations)
> >   if (tree locals = extract_local_specs (pattern, complain))
> > extra = tree_cons (NULL_TREE, extra, locals);
> > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires29.C 
> > b/gcc/testsuite/g++.dg/cpp2a/concepts-requires29.C
> > new file mode 100644
> > index 000..5118df978c9
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires29.C
> > @@ -0,0 +1,18 @@
> > +// PR c++/103105
> > +// { dg-do compile { target c++20 } }
> > +
> > +template class A;
> > +
> > +template
> > +using wrap = A<1 != (0 + ... + requires { Ts(); })>;
> > +
> > +template using type = wrap;
> > +
> > +using ty0 = type<>;
> > +using ty0 = A;
> > +
> > +using ty1 = type;
> > +using ty1 = A;
> > +
> > +using ty2 = type;
> > +using ty2 = A;
> > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires29a.C 
> > b/gcc/testsuite/g++.dg/cpp2a/concepts-requires29a.C
> > new file mode 100644
> > index 000..c41c1e6d039
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires29a.C
> > @@ -0,0 +1,23 @@
> > +// PR c++/103105
> > +// { dg-do compile { target c++20 } }
> > +
> > +template struct list;
> > +template struct A;
> > +
> > +template
> > +using wrap = A<1 != (0 + ... + requires { T() = Ts(); })>;
> > +
> > +template
> > +using type = list...>;
> > +
> > +using ty0 = type<>;
> > +using ty0 = list<>;
> > +
> > +using ty1 = type;
> > +using ty1 = list>;
> > +
> > +using ty2 = type;
> > +using ty2 = list, A>;
> > +
> > +using ty3 = type;
> > +using ty3 = list, A, A>;
>



[PATCH] c++: requires-expr in pack expansion using pack [PR103105]

2022-04-12 Thread Patrick Palka via Gcc-patches
Here after dependent substitution of {Ts...} into the alias 'wrap',
since we never partially instantiate a requires-expr, we end up with a
requires-expr whose REQUIRES_EXPR_EXTRA_ARGS contains an
ARGUMENT_PACK_SELECT (which just resolves to the parameter pack Ts).
Then when looking up the resulting dependent specialization of A, we
crash from iterative_hash_template_arg since it deliberately doesn't
handle ARGUMENT_PACK_SELECT.

Like with r12-7102-gdb5f1c17031ad8, it seems the right fix here is to
resolve ARGUMENT_PACK_SELECT arguments before storing them into an
extra args tree (such as REQUIRES_EXPR).

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk/11?  For 11, we'd need to backport r12-7102 as a prereq.

PR c++/103105
PR c++/103706

gcc/cp/ChangeLog:

* pt.cc (build_extra_args): Call preserve_args.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts-requires29.C: New test.
* g++.dg/cpp2a/concepts-requires29a.C: New test.
---
 gcc/cp/pt.cc  |  2 +-
 .../g++.dg/cpp2a/concepts-requires29.C| 18 +++
 .../g++.dg/cpp2a/concepts-requires29a.C   | 23 +++
 3 files changed, 42 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-requires29.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-requires29a.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 78519562953..84712e6fc2f 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -13048,7 +13048,7 @@ build_extra_args (tree pattern, tree args, 
tsubst_flags_t complain)
 {
   /* Make a copy of the extra arguments so that they won't get changed
  out from under us.  */
-  tree extra = copy_template_args (args);
+  tree extra = preserve_args (copy_template_args (args), /*cow_p=*/false);
   if (local_specializations)
 if (tree locals = extract_local_specs (pattern, complain))
   extra = tree_cons (NULL_TREE, extra, locals);
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires29.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-requires29.C
new file mode 100644
index 000..5118df978c9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires29.C
@@ -0,0 +1,18 @@
+// PR c++/103105
+// { dg-do compile { target c++20 } }
+
+template class A;
+
+template
+using wrap = A<1 != (0 + ... + requires { Ts(); })>;
+
+template using type = wrap;
+
+using ty0 = type<>;
+using ty0 = A;
+
+using ty1 = type;
+using ty1 = A;
+
+using ty2 = type;
+using ty2 = A;
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires29a.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-requires29a.C
new file mode 100644
index 000..c41c1e6d039
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires29a.C
@@ -0,0 +1,23 @@
+// PR c++/103105
+// { dg-do compile { target c++20 } }
+
+template struct list;
+template struct A;
+
+template
+using wrap = A<1 != (0 + ... + requires { T() = Ts(); })>;
+
+template
+using type = list...>;
+
+using ty0 = type<>;
+using ty0 = list<>;
+
+using ty1 = type;
+using ty1 = list>;
+
+using ty2 = type;
+using ty2 = list, A>;
+
+using ty3 = type;
+using ty3 = list, A, A>;
-- 
2.36.0.rc0



[PATCH] c++: respect complain for -Wctad-maybe-unsupported [PR105143]

2022-04-06 Thread Patrick Palka via Gcc-patches
We were attempting to issue a -Wctad-maybe-unsupported warning even when
complain=tf_none, which led to a crash in the first testcase below and a
bogus error during SFINAE in the second testcase.

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

PR c++/105143

gcc/cp/ChangeLog:

* pt.cc (do_class_deduction): Check complain before issuing a
-Wctad-maybe-unsupported warning.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/nodiscard1.C: New test.
* g++.dg/warn/Wctad-maybe-unsupported4.C: New test.
---
 gcc/cp/pt.cc|  2 +-
 gcc/testsuite/g++.dg/cpp2a/nodiscard1.C | 13 +
 .../g++.dg/warn/Wctad-maybe-unsupported4.C  | 12 
 3 files changed, 26 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/nodiscard1.C
 create mode 100644 gcc/testsuite/g++.dg/warn/Wctad-maybe-unsupported4.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 1f0231f70e6..1805fa68440 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -30075,7 +30075,7 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
 
   /* If CTAD succeeded but the type doesn't have any explicit deduction
  guides, this deduction might not be what the user intended.  */
-  if (fndecl != error_mark_node && !any_dguides_p)
+  if ((complain & tf_warning) && fndecl != error_mark_node && !any_dguides_p)
 {
   if ((!DECL_IN_SYSTEM_HEADER (fndecl)
   || global_dc->dc_warn_system_headers)
diff --git a/gcc/testsuite/g++.dg/cpp2a/nodiscard1.C 
b/gcc/testsuite/g++.dg/cpp2a/nodiscard1.C
new file mode 100644
index 000..c3c5094b619
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nodiscard1.C
@@ -0,0 +1,13 @@
+// PR c++/105143
+// { dg-do compile { target c++20 } }
+// We used to crash here with "Error reporting routines re-entered".
+
+template struct A { };
+
+template using type = int;
+
+template [[nodiscard]] type get();
+
+int main() {
+  get<{}>(); // { dg-warning "nodiscard" }
+}
diff --git a/gcc/testsuite/g++.dg/warn/Wctad-maybe-unsupported4.C 
b/gcc/testsuite/g++.dg/warn/Wctad-maybe-unsupported4.C
new file mode 100644
index 000..0d0e2fb45eb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wctad-maybe-unsupported4.C
@@ -0,0 +1,12 @@
+// PR c++/105143
+// { dg-do compile { target c++17 } }
+// { dg-additional-options "-Werror=ctad-maybe-unsupported" }
+
+template struct A { };
+
+template class TT> auto f(...) -> decltype(TT()); // #1
+template class TT> void f(int); // #2
+
+int main() {
+  f(0); // Calls #2 without issuing a -Wctad-maybe-unsupported diagnostic.
+}
-- 
2.36.0.rc0



[PATCH] c++: implicit guides should inherit class constraints [PR104873]

2022-04-01 Thread Patrick Palka via Gcc-patches
An implicit guide already inherits the (rewritten) constraints of the
constructor.  Thus it seems natural that the guide must also inherit
the constraints of the class template, since a constructor's constraints
might assume the class's constraints are satisfied, and therefore
checking these two sets of constraints "out of order" may result in hard
errors as in the first testcase below.

This patch makes implicit guides inherit the constraints of the class
template (even for unconstrained constructors, and even for the copy
deduction candidate).

In passing, this patch gives implicit guides a trailing return type
since that's how they're depicted in the standard (e.g.
[over.match.class.deduct]/6); this changes the order of substitution
into implicit guides in a probably negligible way, especially now that
they inherit the class constraints.

The parameter_mapping_equivalent_p change is to avoid an ICE in the last
testcase below (described within), reduced from a cmcstl2 testsuite ICE.

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look like
the right approach?

PR c++/104873

gcc/cp/ChangeLog:

* constraint.cc (parameter_mapping_equivalent_p): Relax assert
to expect equivalence not identity of template parameters.
* pt.cc (build_deduction_guide): Propagate the class's
constraints to the deduction guide.  Set TYPE_HAS_LATE_RETURN_TYPE
on the function type.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts-ctad5.C: New test.
* g++.dg/cpp2a/concepts-ctad6.C: New test.
* g++.dg/cpp2a/concepts-ctad6a.C: New test.
* g++.dg/cpp2a/concepts-ctad7.C: New test.
---
 gcc/cp/constraint.cc |  2 +-
 gcc/cp/pt.cc | 26 ++
 gcc/testsuite/g++.dg/cpp2a/concepts-ctad5.C  | 29 
 gcc/testsuite/g++.dg/cpp2a/concepts-ctad6.C  | 19 +
 gcc/testsuite/g++.dg/cpp2a/concepts-ctad6a.C | 19 +
 gcc/testsuite/g++.dg/cpp2a/concepts-ctad7.C  | 26 ++
 6 files changed, 120 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-ctad5.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-ctad6.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-ctad6a.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-ctad7.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 94f6222b436..6cbb182dda2 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -604,7 +604,7 @@ parameter_mapping_equivalent_p (tree t1, tree t2)
   tree map2 = ATOMIC_CONSTR_MAP (t2);
   while (map1 && map2)
 {
-  gcc_checking_assert (TREE_VALUE (map1) == TREE_VALUE (map2));
+  gcc_checking_assert (cp_tree_equal (TREE_VALUE (map1), TREE_VALUE 
(map2)));
   tree arg1 = TREE_PURPOSE (map1);
   tree arg2 = TREE_PURPOSE (map2);
   if (!template_args_equal (arg1, arg2))
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 75ed9a34018..966e6d90d3a 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -29261,6 +29261,10 @@ build_deduction_guide (tree type, tree ctor, tree 
outer_args, tsubst_flags_t com
   /* Discard the 'this' parameter.  */
   fparms = FUNCTION_ARG_CHAIN (ctor);
   fargs = TREE_CHAIN (DECL_ARGUMENTS (ctor));
+  /* The guide's constraints consist of the class template's constraints
+followed by the constructor's rewritten constraints.  We start
+with the constructor's constraints (since we need to rewrite them),
+and prepend the class template's constraints later.  */
   ci = get_constraints (ctor);
   loc = DECL_SOURCE_LOCATION (ctor);
   explicit_p = DECL_NONCONVERTING_P (ctor);
@@ -29362,6 +29366,27 @@ build_deduction_guide (tree type, tree ctor, tree 
outer_args, tsubst_flags_t com
return error_mark_node;
 }
 
+  /* Prepend the class template's constraints to the constructor's rewritten
+ constraints (if any).  */
+  if (tree class_ci = get_constraints (CLASSTYPE_TI_TEMPLATE (type)))
+{
+  if (outer_args)
+   {
+ /* FIXME: As above.  */
+ ++processing_template_decl;
+ class_ci = tsubst_constraint_info (class_ci, outer_args,
+complain, ctor);
+ --processing_template_decl;
+   }
+  if (ci)
+   ci = build_constraints (combine_constraint_expressions
+   (CI_TEMPLATE_REQS (class_ci),
+CI_TEMPLATE_REQS (ci)),
+   CI_DECLARATOR_REQS (ci));
+  else
+   ci = copy_node (class_ci);
+}
+
   if (!memtmpl)
 {
   /* Copy the parms so we can set DECL_PRIMARY_TEMPLATE.  */
@@ -29371,6 +29396,7 @@ build_deduction_guide (tree type, tree ctor, tree 
outer_args, tsubst_flags_t com
 }
 
   tree fntype = build_function_type (type, fparms);
+  TYPE_HAS_LATE_RETURN_TYPE (fntype) = true;
   tree ded_fn = 

Re: [pushed] c++: parse trivial DMI immediately [PR96645]

2022-03-31 Thread Patrick Palka via Gcc-patches
On Wed, 30 Mar 2022, Jason Merrill via Gcc-patches wrote:

> The recent change to reject __is_constructible for nested classes with DMI
> is breaking some code loudly that was previously only silently broken.
> Let's allow simple cases by immediately parsing DMI that do no name lookup;
> then being in complete class scope makes no difference.

Not sure if this is a problem in practice but it seems the initializer
processing step of cp_parser_late_parse_one_default_arg may involve name
lookup even if the parse itself didn't:

  struct A {
struct B {
  const A  = {};
};
  };

We used to accept this (very contrived example), but now reject with

  error: invalid use of incomplete type ‘const struct A’

> 
> Tested x86_64-pc-linux-gnu, applying to trunk.
> 
>   PR c++/96645
> 
> gcc/cp/ChangeLog:
> 
>   * parser.cc (cp_parser_early_parsing_nsdmi): New.
>   (cp_parser_member_declaration): Call it.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp0x/nsdmi10.C: Now OK.
>   * g++.dg/ext/is_constructible3.C: Likewise.
>   * g++.dg/ext/is_constructible7.C: Likewise.
> ---
>  gcc/cp/parser.cc | 28 +++-
>  gcc/testsuite/g++.dg/cpp0x/nsdmi10.C |  4 +--
>  gcc/testsuite/g++.dg/ext/is_constructible3.C |  2 +-
>  gcc/testsuite/g++.dg/ext/is_constructible7.C |  3 +--
>  4 files changed, 31 insertions(+), 6 deletions(-)
> 
> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> index 7e1c777364e..63c8af1c722 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -2701,6 +2701,8 @@ static tree cp_parser_late_parse_one_default_arg
>(cp_parser *, tree, tree, tree);
>  static void cp_parser_late_parsing_nsdmi
>(cp_parser *, tree);
> +static bool cp_parser_early_parsing_nsdmi
> +  (cp_parser *, tree);
>  static void cp_parser_late_parsing_default_args
>(cp_parser *, tree);
>  static tree cp_parser_sizeof_operand
> @@ -27478,7 +27480,8 @@ cp_parser_member_declaration (cp_parser* parser)
> if (DECL_DECLARES_FUNCTION_P (decl))
>   cp_parser_save_default_args (parser, STRIP_TEMPLATE (decl));
> else if (TREE_CODE (decl) == FIELD_DECL
> -&& DECL_INITIAL (decl))
> +&& DECL_INITIAL (decl)
> +&& !cp_parser_early_parsing_nsdmi (parser, decl))
>   /* Add DECL to the queue of NSDMI to be parsed later.  */
>   vec_safe_push (unparsed_nsdmis, decl);
>   }
> @@ -32292,6 +32295,29 @@ cp_parser_late_parsing_nsdmi (cp_parser *parser, 
> tree field)
>DECL_INITIAL (field) = def;
>  }
>  
> +/* If the DEFERRED_PARSE for FIELD is safe to parse immediately, do so.
> +   Returns true if deferred parsing is no longer needed.  */
> +
> +static bool
> +cp_parser_early_parsing_nsdmi (cp_parser *parser, tree field)
> +{
> +  tree init = DECL_INITIAL (field);
> +  if (TREE_CODE (init) != DEFERRED_PARSE)
> +return true;
> +
> +  cp_token_cache *tokens = DEFPARSE_TOKENS (init);
> +  for (cp_token *p = tokens->first; p != tokens->last; ++p)
> +if (p->type == CPP_NAME
> + || p->keyword == RID_THIS
> + || p->keyword == RID_OPERATOR)
> +  /* There's a name to look up or 'this', give up.  */
> +  return false;
> +
> +  /* It's trivial, parse now.  */
> +  cp_parser_late_parsing_nsdmi (parser, field);
> +  return true;
> +}
> +
>  /* FN is a FUNCTION_DECL which may contains a parameter with an
> unparsed DEFERRED_PARSE.  Parse the default args now.  This function
> assumes that the current scope is the scope in which the default
> diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi10.C 
> b/gcc/testsuite/g++.dg/cpp0x/nsdmi10.C
> index d8588b7f29e..a965f7bc333 100644
> --- a/gcc/testsuite/g++.dg/cpp0x/nsdmi10.C
> +++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi10.C
> @@ -6,7 +6,7 @@ struct A1 {
>  int y1 = 1;
>};
>  
> -  A1(const B1& opts = B1()) {}  // { dg-error "default member initializer" }
> +  A1(const B1& opts = B1()) {}
>  };
>  
>  struct A2 {
> @@ -14,5 +14,5 @@ struct A2 {
>  int x2, y2 = 1;
>};
>  
> -  A2(const B2& opts = B2()) {}  // { dg-error "default member initializer" }
> +  A2(const B2& opts = B2()) {}
>  };
> diff --git a/gcc/testsuite/g++.dg/ext/is_constructible3.C 
> b/gcc/testsuite/g++.dg/ext/is_constructible3.C
> index 305751d28e2..c7c58746cd0 100644
> --- a/gcc/testsuite/g++.dg/ext/is_constructible3.C
> +++ b/gcc/testsuite/g++.dg/ext/is_constructible3.C
> @@ -8,7 +8,7 @@ struct A {
>  B() = default;
>};
>  
> -  static constexpr bool v = __is_constructible (B); // { dg-error "member 
> initializer" }
> +  static constexpr bool v = __is_constructible (B);
>  
>  };
>  
> diff --git a/gcc/testsuite/g++.dg/ext/is_constructible7.C 
> b/gcc/testsuite/g++.dg/ext/is_constructible7.C
> index 76a63bba5d0..013a1df03c6 100644
> --- a/gcc/testsuite/g++.dg/ext/is_constructible7.C
> +++ b/gcc/testsuite/g++.dg/ext/is_constructible7.C
> @@ -12,7 +12,7 @@ using true_type = 

[PATCH] c++: deduction for dependent class type of NTTP [PR105110]

2022-03-30 Thread Patrick Palka via Gcc-patches
Here deduction for the P/A pair V/a spuriously fails with

  types ‘A’ and ‘const A’ have incompatible cv-qualifiers

because the argument type is const, whereas the parameter type is
non-const.

Since the type of an NTTP is always cv-unqualified, it seems natural to
ignore cv-qualifiers on the argument type before attempting to unify the
two types.

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

PR c++/105110

gcc/cp/ChangeLog:

* pt.cc (unify) : Ignore cv-quals on
on the argument type of an NTTP before deducing from it.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/nontype-class52.C: New test.
---
 gcc/cp/pt.cc |  5 +++--
 gcc/testsuite/g++.dg/cpp2a/nontype-class52.C | 13 +
 2 files changed, 16 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class52.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 1acb5990c5c..cdd75d3b6ac 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -24271,8 +24271,9 @@ unify (tree tparms, tree targs, tree parm, tree arg, 
int strict,
  && !(strict & UNIFY_ALLOW_INTEGER)
  && TEMPLATE_PARM_LEVEL (parm) <= TMPL_ARGS_DEPTH (targs))
{
- /* Deduce it from the non-type argument.  */
- tree atype = TREE_TYPE (arg);
+ /* Deduce it from the non-type argument.  As above, ignore
+top-level quals here too.  */
+ tree atype = cv_unqualified (TREE_TYPE (arg));
  RECUR_AND_CHECK_FAILURE (tparms, targs,
   tparm, atype,
   UNIFY_ALLOW_NONE, explain_p);
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class52.C 
b/gcc/testsuite/g++.dg/cpp2a/nontype-class52.C
new file mode 100644
index 000..56163376afb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class52.C
@@ -0,0 +1,13 @@
+// PR c++/105110
+// { dg-do compile { target c++20 } }
+
+template struct A { };
+
+template struct B { };
+
+template V> void f(B);
+
+int main() {
+  constexpr A a;
+  f(B{});
+}
-- 
2.35.1.693.g805e0a6808



Re: [PATCH] c++: ICE with failed __is_constructible constraint [PR100474]

2022-03-30 Thread Patrick Palka via Gcc-patches
On Tue, 29 Mar 2022, Jason Merrill wrote:

> On 3/29/22 15:22, Patrick Palka wrote:
> > Here we're crashing when diagnosing a failed __is_constructible constraint
> > because diagnose_atomic_constraint don't know how to diagnose a trait
> > that diagnose_trait_expr doesn't specifically handle.  This patch fixes
> > this by falling through to the default case in this situation.
> > 
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > trunk and perhaps 11?
> 
> Hmm, it seems reasonable, but I think it would be better to actually handle
> all the traits.  Removing the default, I get
> 
> > constraint.cc:3585:10: warning: enumeration value ‘CPTK_BASES’ not handled
> > in switch [-Wswitch]
> > constraint.cc:3585:10: warning: enumeration value ‘CPTK_DIRECT_BASES’ not
> > handled in switch [-Wswitch]
> > constraint.cc:3585:10: warning: enumeration value ‘CPTK_UNDERLYING_TYPE’ not
> > handled in switch [-Wswitch]
> 
> These we don't need to handle.
> 
> > constraint.cc:3585:10: warning: enumeration value
> > ‘CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS’ not handled in switch \
> > constraint.cc:3585:10: warning: enumeration value ‘CPTK_IS_AGGREGATE’ not
> > handled in switch [-Wswitch]
> > constraint.cc:3585:10: warning: enumeration value
> > ‘CPTK_IS_TRIVIALLY_ASSIGNABLE’ not handled in switch [-Wswit\
> > constraint.cc:3585:10: warning: enumeration value
> > ‘CPTK_IS_TRIVIALLY_CONSTRUCTIBLE’ not handled in switch [-Ws\
> > constraint.cc:3585:10: warning: enumeration value
> > ‘CPTK_IS_TRIVIALLY_COPYABLE’ not handled in switch [-Wswitch\
> > constraint.cc:3585:10: warning: enumeration value ‘CPTK_IS_ASSIGNABLE’ not
> > handled in switch [-Wswitch]
> > constraint.cc:3585:10: warning: enumeration value ‘CPTK_IS_CONSTRUCTIBLE’
> > not handled in switch [-Wswitch]
> > constraint.cc:3585:10: warning: enumeration value
> > ‘CPTK_IS_NOTHROW_ASSIGNABLE’ not handled in switch [-Wswitch\
> > constraint.cc:3585:10: warning: enumeration value
> > ‘CPTK_IS_NOTHROW_CONSTRUCTIBLE’ not handled in switch [-Wswi\
> 
> These we should.
> 
> I think we should leave off the default so that when we add more traits we get
> a warning that we need to handle them here.

Sounds good, like so?

-- >8 --

Subject: [PATCH] c++: ICE with failed __is_constructible constraint [PR100474]

Here we're crashing when diagnosing a failed __is_constructible constraint
because diagnose_trait_expr doesn't recognize this trait (along with a
bunch of other traits).  Fix this by adding handling for all remaining
traits and removing the default case so that when we add a new trait we
get a warning that diagnose_trait_expr needs to handle it.

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

PR c++/100474

gcc/cp/ChangeLog:

* constraint.cc (diagnose_trait_expr): Handle all remaining
traits appropriately.  Remove default case.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts-traits3.C: New test.
---
 gcc/cp/constraint.cc  | 41 +++-
 gcc/testsuite/g++.dg/cpp2a/concepts-traits3.C | 66 +++
 2 files changed, 106 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-traits3.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c5a991b9e71..b970ac9772d 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3654,7 +3654,46 @@ diagnose_trait_expr (tree expr, tree args)
 case CPTK_IS_UNION:
   inform (loc, "  %qT is not a union", t1);
   break;
-default:
+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 % 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 (!t2)
+   inform (loc, "  %qT is not trivially default constructible", t1);
+  else
+   inform (loc, "  %qT is not trivially constructible from %qE", t1, t2);
+  break;
+case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
+  if (!t2)
+   inform (loc, &q

[PATCH] c++: ICE with failed __is_constructible constraint [PR100474]

2022-03-29 Thread Patrick Palka via Gcc-patches
Here we're crashing when diagnosing a failed __is_constructible constraint
because diagnose_atomic_constraint don't know how to diagnose a trait
that diagnose_trait_expr doesn't specifically handle.  This patch fixes
this by falling through to the default case in this situation.

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

PR c++/100474

gcc/cp/ChangeLog:

* constraint.cc (diagnose_trait_expr): Rename to ...
(maybe_diagnose_trait_expr): ... this.  Return a boolean
indicating whether we handled the trait.
(diagnose_atomic_constraint) : Fall through to
the default case if maybe_diagnose_trait_expr returns false.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts-traits3.C: New test.
---
 gcc/cp/constraint.cc  | 16 +---
 gcc/testsuite/g++.dg/cpp2a/concepts-traits3.C | 10 ++
 2 files changed, 19 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-traits3.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c5a991b9e71..27b1b9bb659 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3567,10 +3567,10 @@ get_constraint_error_location (tree t)
   return input_location;
 }
 
-/* Emit a diagnostic for a failed trait.  */
+/* Maybe emit a friendlier diagnostic for the failed trait.  */
 
-static void
-diagnose_trait_expr (tree expr, tree args)
+static bool
+maybe_diagnose_trait_expr (tree expr, tree args)
 {
   location_t loc = cp_expr_location (expr);
 
@@ -3655,8 +3655,9 @@ diagnose_trait_expr (tree expr, tree args)
   inform (loc, "  %qT is not a union", t1);
   break;
 default:
-  gcc_unreachable ();
+  return false;
 }
+  return true;
 }
 
 /* Diagnose a substitution failure in the atomic constraint T using ARGS.  */
@@ -3685,9 +3686,6 @@ diagnose_atomic_constraint (tree t, tree args, tree 
result, sat_info info)
   STRIP_ANY_LOCATION_WRAPPER (expr);
   switch (TREE_CODE (expr))
 {
-case TRAIT_EXPR:
-  diagnose_trait_expr (expr, args);
-  break;
 case REQUIRES_EXPR:
   gcc_checking_assert (info.diagnose_unsatisfaction_p ());
   /* Clear in_decl before replaying the substitution to avoid emitting
@@ -3696,6 +3694,10 @@ diagnose_atomic_constraint (tree t, tree args, tree 
result, sat_info info)
   info.in_decl = NULL_TREE;
   tsubst_requires_expr (expr, args, info);
   break;
+case TRAIT_EXPR:
+  if (maybe_diagnose_trait_expr (expr, args))
+   break;
+  /* Fall through.  */
 default:
   if (!same_type_p (TREE_TYPE (result), boolean_type_node))
error_at (loc, "constraint %qE has type %qT, not %",
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-traits3.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-traits3.C
new file mode 100644
index 000..33152242988
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-traits3.C
@@ -0,0 +1,10 @@
+// PR c++/100474
+// { dg-do compile { target c++20 } }
+
+template
+concept C = __is_constructible(T, Args...); // { dg-message "evaluated to 
'false'" }
+struct S {
+  S() = delete;
+};
+
+static_assert(C); // { dg-error "assert" }
-- 
2.35.1.677.gabf474a5dd



[committed] c-family: Add -Wmisleading-indentation testcase [PR71637]

2022-03-29 Thread Patrick Palka via Gcc-patches
We no longer emit a bogus warning for the below testcase after
r11-3266-g4839de55e2c986.

Tested on x86_64-pc-linux-gnu, committed to trunk as obvious.

PR c++/71637

gcc/testsuite/ChangeLog:

* c-c++-common/Wmisleading-indentation-6.c: New test.
---
 .../c-c++-common/Wmisleading-indentation-6.c  | 11 +++
 1 file changed, 11 insertions(+)
 create mode 100644 gcc/testsuite/c-c++-common/Wmisleading-indentation-6.c

diff --git a/gcc/testsuite/c-c++-common/Wmisleading-indentation-6.c 
b/gcc/testsuite/c-c++-common/Wmisleading-indentation-6.c
new file mode 100644
index 000..5b7dd7fd2fd
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation-6.c
@@ -0,0 +1,11 @@
+/* PR c++/71637  */
+/* { dg-options "-ftrack-macro-expansion=0 -Wmisleading-indentation" }  */
+
+#define m(x) ({ int y; if (x) y=0; else y=1; y; })
+
+int main()
+{
+  int x =
+m(0);
+  return x;
+}
-- 
2.35.1.677.gabf474a5dd



[PATCH] c++: ICE during constrained template friend matching [PR105064]

2022-03-28 Thread Patrick Palka via Gcc-patches
Here during declaration matching for the two constrained template
friends, we crash from maybe_substitute_reqs_for because the second
friend doesn't yet have DECL_TEMPLATE_INFO set (we're being called
indirectly from push_template_decl).

As far as I can tell, this situation happens only when declaring a
constrained template friend within a non-template class (as in the
testcase), in which case the substitution would be a no-op anyway, so it
should be safe to just skip it.  To that end this patch rearranges
maybe_substitute_reqs_for to gracefully handle DECL_TEMPLATE_INFO being
empty.

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

PR c++/105064

gcc/cp/ChangeLog:

* constraint.cc (maybe_substitute_reqs_for): Don't assume
DECL_TEMPLATE_INFO is set.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts-friend9.C: New test.
---
 gcc/cp/constraint.cc  | 13 -
 gcc/testsuite/g++.dg/cpp2a/concepts-friend9.C | 12 
 2 files changed, 16 insertions(+), 9 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-friend9.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index e14578b1721..c5a991b9e71 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -1268,20 +1268,15 @@ remove_constraints (tree t)
for declaration matching.  */
 
 tree
-maybe_substitute_reqs_for (tree reqs, const_tree decl_)
+maybe_substitute_reqs_for (tree reqs, const_tree decl)
 {
   if (reqs == NULL_TREE)
 return NULL_TREE;
 
-  tree decl = CONST_CAST_TREE (decl_);
-  tree result = STRIP_TEMPLATE (decl);
-
-  if (DECL_UNIQUE_FRIEND_P (result))
+  decl = STRIP_TEMPLATE (decl);
+  if (DECL_UNIQUE_FRIEND_P (decl) && DECL_TEMPLATE_INFO (decl))
 {
-  tree tmpl = decl;
-  if (TREE_CODE (decl) != TEMPLATE_DECL)
-   tmpl = DECL_TI_TEMPLATE (result);
-
+  tree tmpl = DECL_TI_TEMPLATE (decl);
   tree gargs = generic_targs_for (tmpl);
   processing_template_decl_sentinel s;
   if (uses_template_parms (gargs))
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-friend9.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-friend9.C
new file mode 100644
index 000..09054d23d5d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-friend9.C
@@ -0,0 +1,12 @@
+// PR c++/105064
+// { dg-do compile { target c++20 } }
+
+struct A {
+  template
+  friend void f(T) requires true;
+};
+
+struct B {
+  template
+  friend void f(T) requires true;
+};
-- 
2.35.1.677.gabf474a5dd



[PATCH] c++: reject concept w/ multiple tparm lists [PR105067]

2022-03-28 Thread Patrick Palka via Gcc-patches
We weren't rejecting a concept declared with multiple template
parameter lists.

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

PR c++/105067

gcc/cp/ChangeLog:

* pt.cc (finish_concept_definition): Require that a concept is
declared with exactly one template parameter list.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts-err4.C: New test.
---
 gcc/cp/pt.cc   | 6 ++
 gcc/testsuite/g++.dg/cpp2a/concepts-err4.C | 6 ++
 2 files changed, 12 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-err4.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 173bc3a8c7f..bd937499934 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -28775,6 +28775,12 @@ finish_concept_definition (cp_expr id, tree init)
   return error_mark_node;
 }
 
+  if (current_template_depth > 1)
+{
+  error_at (loc, "concept %qE has multiple template parameter lists", *id);
+  return error_mark_node;
+}
+
   /* Initially build the concept declaration; its type is bool.  */
   tree decl = build_lang_decl_loc (loc, CONCEPT_DECL, *id, boolean_type_node);
   DECL_CONTEXT (decl) = current_scope ();
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-err4.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-err4.C
new file mode 100644
index 000..57a96a095c7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-err4.C
@@ -0,0 +1,6 @@
+// PR c++/105067
+// { dg-do compile { target c++20 } }
+
+template
+template
+concept C = true; // { dg-error "parameter list" }
-- 
2.35.1.677.gabf474a5dd



[PATCH] c++: ICE when building builtin operator->* set [PR103455]

2022-03-25 Thread Patrick Palka via Gcc-patches
When constructing the builtin operator->* candidate set according to
the available conversion functions for each operand type, we end up
considering a candidate with C1=T (a TEMPLATE_TYPE_PARM) and C2=F,
during which we crash from lookup_base because dependent_type_p sees
a TEMPLATE_TYPE_PARM when processing_template_decl is cleared.

Sidestepping the question of whether we should be considering a
dependent conversion function here in the first place (which I'm not
sure about), it seems futile to check DERIVED_FROM_P for anything other
than an actual class type, so this patch fixes this ICE by guarding
the DERIVED_FROM_P test with CLASS_TYPE_P instead of MAYBE_CLASS_TYPE_P.

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

PR c++/103455

gcc/cp/ChangeLog:

* call.cc (add_builtin_candidate) : Check
CLASS_TYPE_P instead of MAYBE_CLASS_TYPE_P.

gcc/testsuite/ChangeLog:

* g++.dg/overload/builtin6.C: New test.
---
 gcc/cp/call.cc   |  2 +-
 gcc/testsuite/g++.dg/overload/builtin6.C | 14 ++
 2 files changed, 15 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/overload/builtin6.C

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index ec6c5d5baa2..dfe370d685d 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -2821,7 +2821,7 @@ add_builtin_candidate (struct z_candidate **candidates, 
enum tree_code code,
  tree c1 = TREE_TYPE (type1);
  tree c2 = TYPE_PTRMEM_CLASS_TYPE (type2);
 
- if (MAYBE_CLASS_TYPE_P (c1) && DERIVED_FROM_P (c2, c1)
+ if (CLASS_TYPE_P (c1) && DERIVED_FROM_P (c2, c1)
  && (TYPE_PTRMEMFUNC_P (type2)
  || is_complete (TYPE_PTRMEM_POINTED_TO_TYPE (type2
break;
diff --git a/gcc/testsuite/g++.dg/overload/builtin6.C 
b/gcc/testsuite/g++.dg/overload/builtin6.C
new file mode 100644
index 000..25e45040094
--- /dev/null
+++ b/gcc/testsuite/g++.dg/overload/builtin6.C
@@ -0,0 +1,14 @@
+// PR c++/103455
+
+struct A { };
+
+struct B {
+  operator A*() const;
+  template operator T*() const;
+};
+
+typedef void (A::*F)();
+
+void foo(B b, F f) {
+  (b->*f)();
+}
-- 
2.35.1.655.ga68dfadae5



[PATCH] c++: diagnosing if-stmt with non-constant branches [PR105050]

2022-03-25 Thread Patrick Palka via Gcc-patches
When an if-stmt is deemed non-constant because both of its branches are
non-constant, we issue a rather generic error which, given that it points
to the 'if' token, misleadingly suggests the condition is at fault:

  constexpr-105050.C:8:3: error: expression ‘’ is not a constant 
expression
  8 |   if (p != q && *p < 0)
|   ^~

This patch clarifies the error message to read:

  constexpr-105050.C:8:3: error: neither branch of ‘if’ is a constant expression
  8 |   if (p != q && *p < 0)
|   ^~

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

PR c++/105050

gcc/cp/ChangeLog:

* constexpr.cc (potential_constant_expression_1) :
Clarify error message when a if-stmt is non-constant because its
branches are non-constant.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1y/constexpr-105050.C: New test.
---
 gcc/cp/constexpr.cc   |  7 ++-
 gcc/testsuite/g++.dg/cpp1y/constexpr-105050.C | 12 
 2 files changed, 18 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-105050.C

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 778680b8270..9c40b051574 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -9439,7 +9439,12 @@ potential_constant_expression_1 (tree t, bool want_rval, 
bool strict, bool now,
}
}
   if (flags & tf_error)
-   error_at (loc, "expression %qE is not a constant expression", t);
+   {
+ if (TREE_CODE (t) == IF_STMT)
+   error_at (loc, "neither branch of % is a constant expression");
+ else
+   error_at (loc, "expression %qE is not a constant expression", t);
+   }
   return false;
 
 case VEC_INIT_EXPR:
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-105050.C 
b/gcc/testsuite/g++.dg/cpp1y/constexpr-105050.C
new file mode 100644
index 000..99d5c9960ac
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-105050.C
@@ -0,0 +1,12 @@
+// PR c++/105050
+// { dg-do compile { target c++14 } }
+
+void g();
+void h();
+
+constexpr void f(int* p, int *q) {
+  if (p != q && *p < 0) // { dg-error "neither branch of 'if' is a constant 
expression" }
+g();
+  else
+h();
+}
-- 
2.35.1.655.ga68dfadae5



Re: [PATCH] c++: memory corruption during name lookup w/ modules [PR99479]

2022-03-25 Thread Patrick Palka via Gcc-patches
On Thu, 17 Mar 2022, Patrick Palka wrote:

> On Tue, Mar 1, 2022 at 8:13 AM Patrick Palka  wrote:
> >
> > On Thu, Feb 17, 2022 at 3:24 PM Patrick Palka  wrote:
> > >
> > > name_lookup::search_unqualified uses a statically allocated vector
> > > in order to avoid repeated reallocation, under the assumption that
> > > the function can't be called recursively.  With modules however,
> > > this assumption turns out to be false, and search_unqualified can
> > > be called recursively as demonstrated by testcase in comment #19
> > > of PR99479[1] where the recursive call causes the vector to get
> > > reallocated which invalidates the reference held by the parent call.
> > >
> > > This patch makes search_unqualified instead use an auto_vec with 16
> > > elements of internal storage (since with the various libraries I tested,
> > > the size of the vector never exceeded 12).  In turn we can simplify the
> > > API of subroutines to take the vector by reference and return void.
> > >
> > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > > trunk?
> >
> > Ping.
> 
> Ping.

Ping (+CC Nathan, I wonder if you can take a look at this patch?)

> 
> >
> > >
> > > [1]: https://gcc.gnu.org/PR99479#c19
> > >
> > > PR c++/99479
> > >
> > > gcc/cp/ChangeLog:
> > >
> > > * name-lookup.cc (name_lookup::using_queue): Change to an
> > > auto_vec (with 16 elements of internal storage).
> > > (name_lookup::queue_namespace): Change return type to void,
> > > take queue parameter by reference and adjust function body
> > > accordingly.
> > > (name_lookup::do_queue_usings): Inline into ...
> > > (name_lookup::queue_usings): ... here.  As in queue_namespace.
> > > (name_lookup::search_unqualified): Don't make queue static,
> > > assume its incoming length is 0, and adjust function body
> > > accordingly.
> > > ---
> > >  gcc/cp/name-lookup.cc | 62 +++
> > >  1 file changed, 22 insertions(+), 40 deletions(-)
> > >
> > > diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
> > > index 93c4eb7193b..5c965d6fba1 100644
> > > --- a/gcc/cp/name-lookup.cc
> > > +++ b/gcc/cp/name-lookup.cc
> > > @@ -429,7 +429,7 @@ class name_lookup
> > >  {
> > >  public:
> > >typedef std::pair using_pair;
> > > -  typedef vec using_queue;
> > > +  typedef auto_vec using_queue;
> > >
> > >  public:
> > >tree name;   /* The identifier being looked for.  */
> > > @@ -528,16 +528,8 @@ private:
> > >bool search_usings (tree scope);
> > >
> > >  private:
> > > -  using_queue *queue_namespace (using_queue *queue, int depth, tree 
> > > scope);
> > > -  using_queue *do_queue_usings (using_queue *queue, int depth,
> > > -   vec *usings);
> > > -  using_queue *queue_usings (using_queue *queue, int depth,
> > > -vec *usings)
> > > -  {
> > > -if (usings)
> > > -  queue = do_queue_usings (queue, depth, usings);
> > > -return queue;
> > > -  }
> > > +  void queue_namespace (using_queue& queue, int depth, tree scope);
> > > +  void queue_usings (using_queue& queue, int depth, vec 
> > > *usings);
> > >
> > >  private:
> > >void add_fns (tree);
> > > @@ -1084,39 +1076,35 @@ name_lookup::search_qualified (tree scope, bool 
> > > usings)
> > >  /* Add SCOPE to the unqualified search queue, recursively add its
> > > inlines and those via using directives.  */
> > >
> > > -name_lookup::using_queue *
> > > -name_lookup::queue_namespace (using_queue *queue, int depth, tree scope)
> > > +void
> > > +name_lookup::queue_namespace (using_queue& queue, int depth, tree scope)
> > >  {
> > >if (see_and_mark (scope))
> > > -return queue;
> > > +return;
> > >
> > >/* Record it.  */
> > >tree common = scope;
> > >while (SCOPE_DEPTH (common) > depth)
> > >  common = CP_DECL_CONTEXT (common);
> > > -  vec_safe_push (queue, using_pair (common, scope));
> > > +  queue.safe_push (using_pair (common, scope));
> > >
> > &g

[PATCH] c++: missing SFINAE for consteval calls [PR104620]

2022-03-24 Thread Patrick Palka via Gcc-patches
Here we weren't respecting SFINAE when evaluating a substituted call to
a consteval function, which caused us to reject the new testcase below.
This patch fixes this by making build_over_call use the SFINAE-friendly
version of cxx_constant_value.

This change causes us to no longer diagnose ahead of time a couple of
invalid non-dependent consteval calls in consteval-if2.C (with
-fchecking=2).  These errors were apparently coming from the call to
fold_non_dependent_expr in build_non_dependent_expr (for the RHS of the +=)
despite complain=tf_none being passed.  Now that build_over_call
respects the value of complain during constant evaluation of a consteval
call, the errors are gone.

That the errors don't occur without -fchecking=2 is a regression caused
by r12-7264-gc19f317a78c0e4 and is the subject of PR104620.  As described
in comment #5, I think it was only an accident that we were diagnosing
these two calls correctly before r12-7264, so perhaps we can live
without them in GCC 12.  To that end this patch just XFAILs the two tests.

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

PR c++/104620

gcc/cp/ChangeLog:

* call.cc (build_over_call): Use cxx_constant_value_sfinae
instead of cxx_constant_value to evaluate a consteval call.
* constexpr.cc (cxx_constant_value_sfinae): Add decl parameter
and pass it to cxx_eval_outermost_constant_expr.
* cp-tree.h (cxx_constant_value_sfinae): Add decl parameter.
* pt.cc (fold_targs_r): Pass NULL_TREE as decl to
cxx_constant_value_sfinae.

gcc/testsuite/ChangeLog:

* g++.dg/cpp23/consteval-if2.C: XFAIL two dg-error tests where
the argument to the non-dependent consteval call is wrapped in
NON_DEPENDENT_EXPR.
* g++.dg/cpp2a/consteval30.C: New test.
---
 gcc/cp/call.cc |  2 +-
 gcc/cp/constexpr.cc|  4 ++--
 gcc/cp/cp-tree.h   |  2 +-
 gcc/cp/pt.cc   |  2 +-
 gcc/testsuite/g++.dg/cpp23/consteval-if2.C |  4 ++--
 gcc/testsuite/g++.dg/cpp2a/consteval30.C   | 12 
 6 files changed, 19 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/consteval30.C

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 23d3fc496b8..ec6c5d5baa2 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -9939,7 +9939,7 @@ build_over_call (struct z_candidate *cand, int flags, 
tsubst_flags_t complain)
obj_arg = TREE_OPERAND (addr, 0);
}
}
- call = cxx_constant_value (call, obj_arg);
+ call = cxx_constant_value_sfinae (call, obj_arg, complain);
  if (obj_arg && !error_operand_p (call))
call = build2 (INIT_EXPR, void_type_node, obj_arg, call);
  call = convert_from_reference (call);
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index a3136ce819d..2163a328e74 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -7959,10 +7959,10 @@ cxx_constant_value (tree t, tree decl)
 /* As above, but respect SFINAE.  */
 
 tree
-cxx_constant_value_sfinae (tree t, tsubst_flags_t complain)
+cxx_constant_value_sfinae (tree t, tree decl, tsubst_flags_t complain)
 {
   bool sfinae = !(complain & tf_error);
-  tree r = cxx_eval_outermost_constant_expr (t, sfinae, true, true);
+  tree r = cxx_eval_outermost_constant_expr (t, sfinae, true, true, false, 
decl);
   if (sfinae && !TREE_CONSTANT (r))
 r = error_mark_node;
   return r;
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 1bd7bc6fca2..2f718852ac1 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -8414,7 +8414,7 @@ extern bool require_constant_expression (tree);
 extern bool require_rvalue_constant_expression (tree);
 extern bool require_potential_rvalue_constant_expression (tree);
 extern tree cxx_constant_value (tree, tree = NULL_TREE);
-extern tree cxx_constant_value_sfinae  (tree, tsubst_flags_t);
+extern tree cxx_constant_value_sfinae  (tree, tree, tsubst_flags_t);
 extern void cxx_constant_dtor  (tree, tree);
 extern tree cxx_constant_init  (tree, tree = NULL_TREE);
 extern tree maybe_constant_value   (tree, tree = NULL_TREE, bool = 
false);
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 715eea27577..173bc3a8c7f 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -19811,7 +19811,7 @@ fold_targs_r (tree targs, tsubst_flags_t complain)
   && !glvalue_p (elt)
   && !TREE_CONSTANT (elt))
{
- elt = cxx_constant_value_sfinae (elt, complain);
+ elt = cxx_constant_value_sfinae (elt, NULL_TREE, complain);
  if (elt == error_mark_node)
return false;
}
diff --git a/gcc/testsuite/g++.dg/cpp23/consteval-if2.C 
b/gcc/testsuite/g++.dg/cpp23/consteval-if2.C
index f7053b91c3c..d1845da9e58 100644
--- a/gcc/testsuite/g++.dg/cpp23/consteval-if2.C
+++ 

Re: [pushed] c++: using from enclosing class template [PR105006]

2022-03-23 Thread Patrick Palka via Gcc-patches
On Wed, 23 Mar 2022, Jason Merrill via Gcc-patches wrote:

> Here, DECL_DEPENDENT_P was false for the second using because Row is
> "the current instantiation", so lookup succeeds.  But since Row itself has a
> dependent using-decl for operator(), the set of functions imported by the
> second using is dependent, so we should set the flag.
> 
> Tested x86_64-pc-linux-gnu, applying to trunk.
> 
>   PR c++/105006
> 
> gcc/cp/ChangeLog:
> 
>   * name-lookup.cc (lookup_using_decl): Set DECL_DEPENDENT_P if lookup
>   finds a dependent using.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/template/using30.C: New test.
> ---
>  gcc/cp/name-lookup.cc   | 15 +++
>  gcc/testsuite/g++.dg/template/using30.C | 13 +
>  2 files changed, 28 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/template/using30.C
> 
> diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
> index 323f96bcd24..ea947fabb7e 100644
> --- a/gcc/cp/name-lookup.cc
> +++ b/gcc/cp/name-lookup.cc
> @@ -5665,6 +5665,21 @@ lookup_using_decl (tree scope, name_lookup )
>   lookup.value = lookup_member (binfo, lookup.name, /*protect=*/2,
> /*want_type=*/false, tf_none);
>  
> +  /* If the lookup in the base contains a dependent using, this
> +  using is also dependent.  */
> +  if (!dependent_p && lookup.value)

I wonder if it'd be worthwhile to also test dependent_type_p (scope) here
here to avoid iterating over the lookup set when it can't possibly contain
a dependent using-decl.

> + {
> +   tree val = lookup.value;
> +   if (tree fns = maybe_get_fns (val))
> + val = fns;
> +   for (tree f: lkp_range (val))
> + if (TREE_CODE (f) == USING_DECL && DECL_DEPENDENT_P (f))
> +   {
> + dependent_p = true;
> + break;
> +   }
> + }
> +
>if (!depscope && b_kind < bk_proper_base)
>   {
> if (cxx_dialect >= cxx20 && lookup.value
> diff --git a/gcc/testsuite/g++.dg/template/using30.C 
> b/gcc/testsuite/g++.dg/template/using30.C
> new file mode 100644
> index 000..914252dd14c
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/template/using30.C
> @@ -0,0 +1,13 @@
> +// PR c++/105006
> +
> +template
> +class Row {
> +  using eT::operator();
> +  void operator()();
> +  class fixed;
> +};
> +
> +template
> +class Row::fixed : Row {
> +  using Row::operator();
> +};
> 
> base-commit: 4a9e92164a547afcf8cd3fc593c7660238ad2d59
> -- 
> 2.27.0
> 
> 



Re: [PATCH] c++: alias template arguments are evaluated [PR101906]

2022-03-22 Thread Patrick Palka via Gcc-patches
On Tue, 22 Mar 2022, Patrick Palka wrote:

> Here we're neglecting to clear cp_unevaluated_operand when substituting
> into the arguments of the alias template-id skip<(T(), 0), T> with T=A,
> which means cp_unevaluated_operand remains set during mark_used for
> A::A() and so we never synthesize it.  Later constant evaluation for
> the substituted template argument (A(), 0) (during coerce_template_parms)
> fails with "'constexpr A::A()' used before its definition" since it was
> never synthesized.

It occurred to me to check the case where 'skip' is a function/variable
template instead of an alias template, and unfortunately seems we run
into the same issue:

  template T skip();  // Function template
  // template T skip; // Variable template

  template
  constexpr unsigned sizeof_() {
return sizeof(skip<(T(), 0), T>());
// return sizeof(skip<(T(), 0), T>);
  }

  struct A {
int m = -1;
  };

  static_assert(sizeof_() == sizeof(A), "");

: In instantiation of ‘constexpr unsigned int sizeof_() [with T = A]’:
:14:25:   required from here
:6:34: error: ‘constexpr A::A()’ used before its definition

We can fix this similarly by clearing cp_unevaluated_operand when
substituting into the arguments of a TEMPLATE_ID_EXPR, but now I'm
worried this cp_unevaluated_operand business might not be the best
approach (despite it being consistent with what tsubst_aggr_type does).

Maybe instantiate_cx_fn_r should be responsible for making sure A::A()
gets synthesized?

> 
> This minimal patch makes us clear cp_unevaluated_operand when
> substituting into the template arguments of an alias template-id, as in
> tsubst_aggr_type.
> 
> (A few lines below we also substitute into the template arguments of a
> class-scope typedef, during which we arguably also should clear
> cp_unevaluated_operand, but I wasn't able to come up with a testcase for
> which this mattered, because if we've named a class-scope typedef, then
> at some point tsubst_aggr_type must have already substituted the class
> scope, which performs the same substitution with cp_unevaluated_operand
> cleared.)
> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk?
> 
>   PR c++/101906
> 
> gcc/cp/ChangeLog:
> 
>   * pt.cc (tsubst): Clear cp_unevaluated_operand when substituting
>   the template arguments of an alias template specialization.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp0x/alias-decl-75.C: New test.
>   * g++.dg/cpp0x/alias-decl-75a.C: New test.
> ---
>  gcc/cp/pt.cc|  6 +-
>  gcc/testsuite/g++.dg/cpp0x/alias-decl-75.C  | 15 +++
>  gcc/testsuite/g++.dg/cpp0x/alias-decl-75a.C | 16 
>  3 files changed, 36 insertions(+), 1 deletion(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-75.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-75a.C
> 
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 7697615ac64..c7116849551 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -15545,7 +15545,11 @@ tsubst (tree t, tree args, tsubst_flags_t complain, 
> tree in_decl)
> /* DECL represents an alias template and we want to
>instantiate it.  */
> tree tmpl = most_general_template (DECL_TI_TEMPLATE (decl));
> -   tree gen_args = tsubst (DECL_TI_ARGS (decl), args, complain, in_decl);
> +   tree gen_args;
> + {
> +   cp_evaluated ev;
> +   gen_args = tsubst (DECL_TI_ARGS (decl), args, complain, in_decl);
> + }
> r = instantiate_alias_template (tmpl, gen_args, complain);
>   }
>else if (DECL_CLASS_SCOPE_P (decl)
> diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-75.C 
> b/gcc/testsuite/g++.dg/cpp0x/alias-decl-75.C
> new file mode 100644
> index 000..c6176751283
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-75.C
> @@ -0,0 +1,15 @@
> +// PR c++/101906
> +// { dg-do compile { target c++11 } }
> +
> +template using skip = T;
> +
> +template
> +constexpr unsigned sizeof_() {
> +  return sizeof(skip<(T(), 0), T>);
> +}
> +
> +struct A {
> +  int m = -1;
> +};
> +
> +static_assert(sizeof_() == sizeof(A), "");
> diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-75a.C 
> b/gcc/testsuite/g++.dg/cpp0x/alias-decl-75a.C
> new file mode 100644
> index 000..ce08a84f6d9
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-75a.C
> @@ -0,0 +1,16 @@
> +// PR c++/101906
> +// Similar to alias-decl-75.C, but where the unevaluated context is a
> +// constraint instead of sizeof.
> +// { dg-do compile { target c++20 } }
> +
> +template using voidify = void;
> +
> +template
> +concept constant_value_initializable
> +  = requires { typename voidify<(T(), 0)>; };
> +
> +struct A {
> +  int m = -1;
> +};
> +
> +static_assert(constant_value_initializable);
> -- 
> 2.35.1.607.gf01e51a7cf
> 
> 


[PATCH] c++: alias template arguments are evaluated [PR101906]

2022-03-22 Thread Patrick Palka via Gcc-patches
Here we're neglecting to clear cp_unevaluated_operand when substituting
into the arguments of the alias template-id skip<(T(), 0), T> with T=A,
which means cp_unevaluated_operand remains set during mark_used for
A::A() and so we never synthesize it.  Later constant evaluation for
the substituted template argument (A(), 0) (during coerce_template_parms)
fails with "'constexpr A::A()' used before its definition" since it was
never synthesized.

This minimal patch makes us clear cp_unevaluated_operand when
substituting into the template arguments of an alias template-id, as in
tsubst_aggr_type.

(A few lines below we also substitute into the template arguments of a
class-scope typedef, during which we arguably also should clear
cp_unevaluated_operand, but I wasn't able to come up with a testcase for
which this mattered, because if we've named a class-scope typedef, then
at some point tsubst_aggr_type must have already substituted the class
scope, which performs the same substitution with cp_unevaluated_operand
cleared.)

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

PR c++/101906

gcc/cp/ChangeLog:

* pt.cc (tsubst): Clear cp_unevaluated_operand when substituting
the template arguments of an alias template specialization.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/alias-decl-75.C: New test.
* g++.dg/cpp0x/alias-decl-75a.C: New test.
---
 gcc/cp/pt.cc|  6 +-
 gcc/testsuite/g++.dg/cpp0x/alias-decl-75.C  | 15 +++
 gcc/testsuite/g++.dg/cpp0x/alias-decl-75a.C | 16 
 3 files changed, 36 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-75.C
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-75a.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 7697615ac64..c7116849551 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -15545,7 +15545,11 @@ tsubst (tree t, tree args, tsubst_flags_t complain, 
tree in_decl)
  /* DECL represents an alias template and we want to
 instantiate it.  */
  tree tmpl = most_general_template (DECL_TI_TEMPLATE (decl));
- tree gen_args = tsubst (DECL_TI_ARGS (decl), args, complain, in_decl);
+ tree gen_args;
+   {
+ cp_evaluated ev;
+ gen_args = tsubst (DECL_TI_ARGS (decl), args, complain, in_decl);
+   }
  r = instantiate_alias_template (tmpl, gen_args, complain);
}
   else if (DECL_CLASS_SCOPE_P (decl)
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-75.C 
b/gcc/testsuite/g++.dg/cpp0x/alias-decl-75.C
new file mode 100644
index 000..c6176751283
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-75.C
@@ -0,0 +1,15 @@
+// PR c++/101906
+// { dg-do compile { target c++11 } }
+
+template using skip = T;
+
+template
+constexpr unsigned sizeof_() {
+  return sizeof(skip<(T(), 0), T>);
+}
+
+struct A {
+  int m = -1;
+};
+
+static_assert(sizeof_() == sizeof(A), "");
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-75a.C 
b/gcc/testsuite/g++.dg/cpp0x/alias-decl-75a.C
new file mode 100644
index 000..ce08a84f6d9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-75a.C
@@ -0,0 +1,16 @@
+// PR c++/101906
+// Similar to alias-decl-75.C, but where the unevaluated context is a
+// constraint instead of sizeof.
+// { dg-do compile { target c++20 } }
+
+template using voidify = void;
+
+template
+concept constant_value_initializable
+  = requires { typename voidify<(T(), 0)>; };
+
+struct A {
+  int m = -1;
+};
+
+static_assert(constant_value_initializable);
-- 
2.35.1.607.gf01e51a7cf



Re: [pushed] c++: designated init and aggregate members [PR102337]

2022-03-22 Thread Patrick Palka via Gcc-patches
On Mon, 21 Mar 2022, Jason Merrill via Gcc-patches wrote:

> Our C++20 designated initializer handling was broken with members of class
> type; we would find the relevant member and then try to find a member of
> the member with the same name.  Or we would sometimes ignore the designator
> entirely.  The former problem is fixed by the change to reshape_init_class,
> the latter by the change to reshape_init_r.
> 
> Tested x86_64-pc-linux-gnu, applying to trunk.
> 
>   PR c++/103337
>   PR c++/102740
>   PR c++/103299
>   PR c++/102538
> 
> gcc/cp/ChangeLog:
> 
>   * decl.cc (reshape_init_class): Avoid looking for designator
>   after we found it.
>   (reshape_init_r): Keep looking for designator.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/ext/flexary3.C: Remove one error.
>   * g++.dg/parse/pr43765.C: Likewise.
>   * g++.dg/cpp2a/desig22.C: New test.
>   * g++.dg/cpp2a/desig23.C: New test.
>   * g++.dg/cpp2a/desig24.C: New test.
>   * g++.dg/cpp2a/desig25.C: New test.
> ---
>  gcc/cp/decl.cc   | 47 +---
>  gcc/testsuite/g++.dg/cpp2a/desig22.C | 11 +++
>  gcc/testsuite/g++.dg/cpp2a/desig23.C | 20 
>  gcc/testsuite/g++.dg/cpp2a/desig24.C | 11 +++
>  gcc/testsuite/g++.dg/cpp2a/desig25.C | 13 
>  gcc/testsuite/g++.dg/ext/flexary3.C  |  2 +-
>  gcc/testsuite/g++.dg/parse/pr43765.C |  6 ++--
>  7 files changed, 101 insertions(+), 9 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/desig22.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/desig23.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/desig24.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/desig25.C
> 
> diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> index 375385e0013..34d9dad9fb0 100644
> --- a/gcc/cp/decl.cc
> +++ b/gcc/cp/decl.cc
> @@ -6598,8 +6598,9 @@ reshape_init_class (tree type, reshape_iter *d, bool 
> first_initializer_p,
>  {
>tree field_init;
>constructor_elt *old_cur = d->cur;
> +  bool direct_desig = false;
>  
> -  /* Handle designated initializers, as an extension.  */
> +  /* Handle C++20 designated initializers.  */
>if (d->cur->index)
>   {
> if (d->cur->index == error_mark_node)
> @@ -6617,7 +6618,10 @@ reshape_init_class (tree type, reshape_iter *d, bool 
> first_initializer_p,
>   }
>   }
> else if (TREE_CODE (d->cur->index) == IDENTIFIER_NODE)
> - field = get_class_binding (type, d->cur->index);
> + {
> +   field = get_class_binding (type, d->cur->index);
> +   direct_desig = true;
> + }
> else
>   {
> if (complain & tf_error)
> @@ -6669,6 +6673,7 @@ reshape_init_class (tree type, reshape_iter *d, bool 
> first_initializer_p,
> break;
> gcc_assert (aafield);
> field = aafield;
> +   direct_desig = false;
>   }
>   }
>  
> @@ -6683,9 +6688,32 @@ reshape_init_class (tree type, reshape_iter *d, bool 
> first_initializer_p,
>  assumed to correspond to no elements of the initializer list.  */
>   goto continue_;
>  
> -  field_init = reshape_init_r (TREE_TYPE (field), d,
> -/*first_initializer_p=*/NULL_TREE,
> -complain);
> +  if (direct_desig)
> + {
> +   /* The designated field F is initialized from this one element:
> +  Temporarily clear the designator so a recursive reshape_init_class
> +  doesn't try to find it again in F, and adjust d->end so we don't
> +  try to use the next initializer to initialize another member of F.
> +
> +  Note that we don't want these changes if we found the designator
> +  inside an anon aggr above; we leave them alone to implement:
> +
> +  "If the element is an anonymous union member and the initializer
> +  list is a brace-enclosed designated- initializer-list, the element
> +  is initialized by the designated-initializer-list { D }, where D
> +  is the designated- initializer-clause naming a member of the
> +  anonymous union member."  */
> +   auto end_ = make_temp_override (d->end, d->cur + 1);
> +   auto idx_ = make_temp_override (d->cur->index, NULL_TREE);

IIUC this override of d->cur->index mutates the underlying CONSTRUCTOR, which
is probably fine, but I wonder if it'd be worthwhile to avoid the mutation by
using a temporary reshape_iter for the recursive call, something like:

  constructor_elt elt = { /*index=*/NULL_TREE, d->cur->value };
  reshape_iter iter = { ,  + 1 };
  field_init = reshape_init_r (TREE_TYPE (field), ,
   /*first_initializer_p=*/NULL_TREE,
   complain);
  d->cur++;

> +   field_init = reshape_init_r (TREE_TYPE (field), d,
> +

Re: [PATCH] c++: memory corruption during name lookup w/ modules [PR99479]

2022-03-17 Thread Patrick Palka via Gcc-patches
On Tue, Mar 1, 2022 at 8:13 AM Patrick Palka  wrote:
>
> On Thu, Feb 17, 2022 at 3:24 PM Patrick Palka  wrote:
> >
> > name_lookup::search_unqualified uses a statically allocated vector
> > in order to avoid repeated reallocation, under the assumption that
> > the function can't be called recursively.  With modules however,
> > this assumption turns out to be false, and search_unqualified can
> > be called recursively as demonstrated by testcase in comment #19
> > of PR99479[1] where the recursive call causes the vector to get
> > reallocated which invalidates the reference held by the parent call.
> >
> > This patch makes search_unqualified instead use an auto_vec with 16
> > elements of internal storage (since with the various libraries I tested,
> > the size of the vector never exceeded 12).  In turn we can simplify the
> > API of subroutines to take the vector by reference and return void.
> >
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > trunk?
>
> Ping.

Ping.

>
> >
> > [1]: https://gcc.gnu.org/PR99479#c19
> >
> > PR c++/99479
> >
> > gcc/cp/ChangeLog:
> >
> > * name-lookup.cc (name_lookup::using_queue): Change to an
> > auto_vec (with 16 elements of internal storage).
> > (name_lookup::queue_namespace): Change return type to void,
> > take queue parameter by reference and adjust function body
> > accordingly.
> > (name_lookup::do_queue_usings): Inline into ...
> > (name_lookup::queue_usings): ... here.  As in queue_namespace.
> > (name_lookup::search_unqualified): Don't make queue static,
> > assume its incoming length is 0, and adjust function body
> > accordingly.
> > ---
> >  gcc/cp/name-lookup.cc | 62 +++
> >  1 file changed, 22 insertions(+), 40 deletions(-)
> >
> > diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
> > index 93c4eb7193b..5c965d6fba1 100644
> > --- a/gcc/cp/name-lookup.cc
> > +++ b/gcc/cp/name-lookup.cc
> > @@ -429,7 +429,7 @@ class name_lookup
> >  {
> >  public:
> >typedef std::pair using_pair;
> > -  typedef vec using_queue;
> > +  typedef auto_vec using_queue;
> >
> >  public:
> >tree name;   /* The identifier being looked for.  */
> > @@ -528,16 +528,8 @@ private:
> >bool search_usings (tree scope);
> >
> >  private:
> > -  using_queue *queue_namespace (using_queue *queue, int depth, tree scope);
> > -  using_queue *do_queue_usings (using_queue *queue, int depth,
> > -   vec *usings);
> > -  using_queue *queue_usings (using_queue *queue, int depth,
> > -vec *usings)
> > -  {
> > -if (usings)
> > -  queue = do_queue_usings (queue, depth, usings);
> > -return queue;
> > -  }
> > +  void queue_namespace (using_queue& queue, int depth, tree scope);
> > +  void queue_usings (using_queue& queue, int depth, vec 
> > *usings);
> >
> >  private:
> >void add_fns (tree);
> > @@ -1084,39 +1076,35 @@ name_lookup::search_qualified (tree scope, bool 
> > usings)
> >  /* Add SCOPE to the unqualified search queue, recursively add its
> > inlines and those via using directives.  */
> >
> > -name_lookup::using_queue *
> > -name_lookup::queue_namespace (using_queue *queue, int depth, tree scope)
> > +void
> > +name_lookup::queue_namespace (using_queue& queue, int depth, tree scope)
> >  {
> >if (see_and_mark (scope))
> > -return queue;
> > +return;
> >
> >/* Record it.  */
> >tree common = scope;
> >while (SCOPE_DEPTH (common) > depth)
> >  common = CP_DECL_CONTEXT (common);
> > -  vec_safe_push (queue, using_pair (common, scope));
> > +  queue.safe_push (using_pair (common, scope));
> >
> >/* Queue its inline children.  */
> >if (vec *inlinees = DECL_NAMESPACE_INLINEES (scope))
> >  for (unsigned ix = inlinees->length (); ix--;)
> > -  queue = queue_namespace (queue, depth, (*inlinees)[ix]);
> > +  queue_namespace (queue, depth, (*inlinees)[ix]);
> >
> >/* Queue its using targets.  */
> > -  queue = queue_usings (queue, depth, NAMESPACE_LEVEL 
> > (scope)->using_directives);
> > -
> > -  return queue;
> > +  queue_usings (queue, depth, NAMESPACE_LEVEL (scope)->using_directives);
> >  }
> >
> >  /* Add the n

[PATCH] c++: further lookup_member simplification

2022-03-15 Thread Patrick Palka via Gcc-patches
As a followup to r12-7656-gffe9c0a0d3564a, this minor patch condenses
the handling of ambiguity and access w.r.t. the value of 'protect' so
that it more clearly matches the function comment.

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

gcc/cp/ChangeLog:

* search.cc (lookup_member): Simplify by handling all values
of protect at once in case of ambiguous lookup.  Don't modify
protect.
---
 gcc/cp/search.cc | 32 +---
 1 file changed, 13 insertions(+), 19 deletions(-)

diff --git a/gcc/cp/search.cc b/gcc/cp/search.cc
index 85e3e7cb487..b86b3a24080 100644
--- a/gcc/cp/search.cc
+++ b/gcc/cp/search.cc
@@ -1168,27 +1168,21 @@ lookup_member (tree xbasetype, tree name, int protect, 
bool want_type,
   if (rval_binfo)
 type = BINFO_TYPE (rval_binfo);
 
-  /* If we are not interested in ambiguities, don't report them;
- just return NULL_TREE.  */
-  if (!protect && lfi.ambiguous)
-return NULL_TREE;
-
-  if (protect == 2)
-{
-  if (lfi.ambiguous)
-   return lfi.ambiguous;
-  else
-   protect = 0;
-}
-
-  if (protect == 1 && lfi.ambiguous)
+  if (lfi.ambiguous)
 {
-  if (complain & tf_error)
+  if (protect == 0)
+   return NULL_TREE;
+  else if (protect == 1)
{
- error ("request for member %qD is ambiguous", name);
- print_candidates (lfi.ambiguous);
+ if (complain & tf_error)
+   {
+ error ("request for member %qD is ambiguous", name);
+ print_candidates (lfi.ambiguous);
+   }
+ return error_mark_node;
}
-  return error_mark_node;
+  else if (protect == 2)
+   return lfi.ambiguous;
 }
 
   if (!rval)
@@ -1213,7 +1207,7 @@ lookup_member (tree xbasetype, tree name, int protect, 
bool want_type,
 
 only the first call to "f" is valid.  However, if the function is
 static, we can check.  */
-  if (protect && !really_overloaded_fn (rval))
+  if (protect == 1 && !really_overloaded_fn (rval))
 {
   tree decl = is_overloaded_fn (rval) ? get_first_fn (rval) : rval;
   decl = strip_using_decl (decl);
-- 
2.35.1.500.gb896f729e2



Re: [PATCH] c++: fold calls to std::move/forward [PR96780]

2022-03-15 Thread Patrick Palka via Gcc-patches
On Tue, 15 Mar 2022, Jason Merrill wrote:

> On 3/15/22 10:03, Patrick Palka wrote:
> > On Mon, 14 Mar 2022, Jason Merrill wrote:
> > 
> > > On 3/14/22 13:13, Patrick Palka wrote:
> > > > On Fri, 11 Mar 2022, Jason Merrill wrote:
> > > > 
> > > > > On 3/10/22 11:27, Patrick Palka wrote:
> > > > > > On Wed, 9 Mar 2022, Jason Merrill wrote:
> > > > > > 
> > > > > > > On 3/1/22 18:08, Patrick Palka wrote:
> > > > > > > > A well-formed call to std::move/forward is equivalent to a cast,
> > > > > > > > but
> > > > > > > > the
> > > > > > > > former being a function call means it comes with bloated debug
> > > > > > > > info,
> > > > > > > > which
> > > > > > > > persists even after the call has been inlined away, for an
> > > > > > > > operation
> > > > > > > > that
> > > > > > > > is never interesting to debug.
> > > > > > > > 
> > > > > > > > This patch addresses this problem in a relatively ad-hoc way by
> > > > > > > > folding
> > > > > > > > calls to std::move/forward into casts as part of the frontend's
> > > > > > > > general
> > > > > > > > expression folding routine.  After this patch with -O2 and a
> > > > > > > > non-checking
> > > > > > > > compiler, debug info size for some testcases decreases by about
> > > > > > > > ~10%
> > > > > > > > and
> > > > > > > > overall compile time and memory usage decreases by ~2%.
> > > > > > > 
> > > > > > > Impressive.  Which testcases?
> > > > > > 
> > > > > > I saw the largest percent reductions in debug file object size in
> > > > > > various tests from cmcstl2 and range-v3, e.g.
> > > > > > test/algorithm/set_symmetric_difference4.cpp and .../rotate_copy.cpp
> > > > > > (which are among their biggest tests).
> > > > > > 
> > > > > > Significant reductions in debug object file size can be observed in
> > > > > > some libstdc++ testcases too, such as a 5.5% reduction in
> > > > > > std/ranges/adaptor/join.cc
> > > > > > 
> > > > > > > 
> > > > > > > Do you also want to handle addressof and as_const in this patch,
> > > > > > > as
> > > > > > > Jonathan
> > > > > > > suggested?
> > > > > > 
> > > > > > Yes, good idea.  Since each of their argument and return types are
> > > > > > indirect types, I think we can use the same NOP_EXPR-based folding
> > > > > > for
> > > > > > them.
> > > > > > 
> > > > > > > 
> > > > > > > I think we can do this now, and think about generalizing more in
> > > > > > > stage
> > > > > > > 1.
> > > > > > > 
> > > > > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, is this
> > > > > > > > something
> > > > > > > > we
> > > > > > > > want to consider for GCC 12?
> > > > > > > > 
> > > > > > > > PR c++/96780
> > > > > > > > 
> > > > > > > > gcc/cp/ChangeLog:
> > > > > > > > 
> > > > > > > > * cp-gimplify.cc (cp_fold) : When 
> > > > > > > > optimizing,
> > > > > > > > fold calls to std::move/forward into simple casts.
> > > > > > > > * cp-tree.h (is_std_move_p, is_std_forward_p): Declare.
> > > > > > > > * typeck.cc (is_std_move_p, is_std_forward_p): Export.
> > > > > > > > 
> > > > > > > > gcc/testsuite/ChangeLog:
> > > > > > > > 
> > > > > > > > * g++.dg/opt/pr96780.C: New test.
> > > > > > > > ---
> > > > > > > >  gcc/cp/cp-gimplify.cc  | 18 ++
> > > > > > > >  gcc/cp/cp-tree.h   |  2 

Re: [PATCH] libstdc++: Ensure that std::from_chars is declared when supported

2022-03-15 Thread Patrick Palka via Gcc-patches
On Mon, 14 Mar 2022, Jonathan Wakely wrote:

> On Mon, 14 Mar 2022 at 14:17, Patrick Palka via Libstdc++
>  wrote:
> >
> > On Fri, 11 Mar 2022, Jonathan Wakely wrote:
> >
> > > Patrick, I think this is right, but please take a look to double check.
> > >
> > > I think we should fix the feature-test macro conditions for gcc-11 too,
> > > although it's a bit more complicated there. It should depend on IEEE
> > > float and double *and* uselocale. We don't need the other changes on the
> > > branch.
> >
> > Don't we still depend on uselocale in GCC 12 for long double from_chars,
> > at least on targets where long double != binary64?
> 
> Not after this patch:
> 
> from_chars(const char* first, const char* last, long double& value,
>   chars_format fmt) noexcept
> {
> -#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 \
> -  && ! USE_STRTOD_FOR_FROM_CHARS
> +#if ! USE_STRTOD_FOR_FROM_CHARS
> +  // Either long double is the same as double, or we can't use strtold.
> +  // In the latter case, this might give an incorrect result (e.g. values
> +  // out of range of double give an error, even if they fit in long double).
> 
> If uselocale isn't available, this defines the long double overload in
> terms of the double one, even if that doesn't always give the right
> answers. That greatly simplifies the preprocessor conditions for when
> it's supported. If the float and double forms are present, so is the
> long double one.

Ah sorry, I had overlooked that part of the patch.  Makes sense and LGTM!



Re: [PATCH] c++: fold calls to std::move/forward [PR96780]

2022-03-15 Thread Patrick Palka via Gcc-patches
On Mon, 14 Mar 2022, Jason Merrill wrote:

> On 3/14/22 13:13, Patrick Palka wrote:
> > On Fri, 11 Mar 2022, Jason Merrill wrote:
> > 
> > > On 3/10/22 11:27, Patrick Palka wrote:
> > > > On Wed, 9 Mar 2022, Jason Merrill wrote:
> > > > 
> > > > > On 3/1/22 18:08, Patrick Palka wrote:
> > > > > > A well-formed call to std::move/forward is equivalent to a cast, but
> > > > > > the
> > > > > > former being a function call means it comes with bloated debug info,
> > > > > > which
> > > > > > persists even after the call has been inlined away, for an operation
> > > > > > that
> > > > > > is never interesting to debug.
> > > > > > 
> > > > > > This patch addresses this problem in a relatively ad-hoc way by
> > > > > > folding
> > > > > > calls to std::move/forward into casts as part of the frontend's
> > > > > > general
> > > > > > expression folding routine.  After this patch with -O2 and a
> > > > > > non-checking
> > > > > > compiler, debug info size for some testcases decreases by about ~10%
> > > > > > and
> > > > > > overall compile time and memory usage decreases by ~2%.
> > > > > 
> > > > > Impressive.  Which testcases?
> > > > 
> > > > I saw the largest percent reductions in debug file object size in
> > > > various tests from cmcstl2 and range-v3, e.g.
> > > > test/algorithm/set_symmetric_difference4.cpp and .../rotate_copy.cpp
> > > > (which are among their biggest tests).
> > > > 
> > > > Significant reductions in debug object file size can be observed in
> > > > some libstdc++ testcases too, such as a 5.5% reduction in
> > > > std/ranges/adaptor/join.cc
> > > > 
> > > > > 
> > > > > Do you also want to handle addressof and as_const in this patch, as
> > > > > Jonathan
> > > > > suggested?
> > > > 
> > > > Yes, good idea.  Since each of their argument and return types are
> > > > indirect types, I think we can use the same NOP_EXPR-based folding for
> > > > them.
> > > > 
> > > > > 
> > > > > I think we can do this now, and think about generalizing more in stage
> > > > > 1.
> > > > > 
> > > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, is this something
> > > > > > we
> > > > > > want to consider for GCC 12?
> > > > > > 
> > > > > > PR c++/96780
> > > > > > 
> > > > > > gcc/cp/ChangeLog:
> > > > > > 
> > > > > > * cp-gimplify.cc (cp_fold) : When optimizing,
> > > > > > fold calls to std::move/forward into simple casts.
> > > > > > * cp-tree.h (is_std_move_p, is_std_forward_p): Declare.
> > > > > > * typeck.cc (is_std_move_p, is_std_forward_p): Export.
> > > > > > 
> > > > > > gcc/testsuite/ChangeLog:
> > > > > > 
> > > > > > * g++.dg/opt/pr96780.C: New test.
> > > > > > ---
> > > > > > gcc/cp/cp-gimplify.cc  | 18 ++
> > > > > > gcc/cp/cp-tree.h   |  2 ++
> > > > > > gcc/cp/typeck.cc   |  6 ++
> > > > > > gcc/testsuite/g++.dg/opt/pr96780.C | 24 
> > > > > > 4 files changed, 46 insertions(+), 4 deletions(-)
> > > > > > create mode 100644 gcc/testsuite/g++.dg/opt/pr96780.C
> > > > > > 
> > > > > > diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
> > > > > > index d7323fb5c09..0b009b631c7 100644
> > > > > > --- a/gcc/cp/cp-gimplify.cc
> > > > > > +++ b/gcc/cp/cp-gimplify.cc
> > > > > > @@ -2756,6 +2756,24 @@ cp_fold (tree x)
> > > > > >   case CALL_EXPR:
> > > > > >   {
> > > > > > +   if (optimize
> > > > > 
> > > > > I think this should check flag_no_inline rather than optimize.
> > > > 
> > > > Sounds good.
> > > > 
> > > > Here's a patch that extends the folding to as_const and addressof (as
>

[PATCH] c++: extraneous access error with ambiguous lookup [PR103177]

2022-03-14 Thread Patrick Palka via Gcc-patches
When a lookup is ambiguous, lookup_member still attempts to check
access of the first member found before diagnosing the ambiguity and
erroring out, which may cause us to issue an extraneous access error
in case of ambiguous lookup as in the testcase below (for B1::foo).

This patch fixes this by swapping the order of the ambiguity and access
checks within lookup_member.  In passing, since the only possible error
that could happen during lookup_field_r is an ambiguity error, we might
as well hardcode that in lookup_member instead and remove the unneeded
lookup_field_info::errstr.

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

PR c++/103177

gcc/cp/ChangeLog:

* search.cc (lookup_field_info::errstr): Remove this data
member.
(lookup_field_r): Don't set errstr.
(lookup_member): Check ambiguity before checking access.
Simplify accordingly after errstr removal.  Exit early upon
error or empty result.

gcc/testsuite/ChangeLog:

* g++.dg/lookup/ambig6.C: New test.
---
 gcc/cp/search.cc | 37 
 gcc/testsuite/g++.dg/lookup/ambig6.C | 18 ++
 2 files changed, 34 insertions(+), 21 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/lookup/ambig6.C

diff --git a/gcc/cp/search.cc b/gcc/cp/search.cc
index 2b8210408fb..85e3e7cb487 100644
--- a/gcc/cp/search.cc
+++ b/gcc/cp/search.cc
@@ -941,8 +941,6 @@ struct lookup_field_info {
   tree ambiguous;
   /* If nonzero, we are looking for types, not data members.  */
   int want_type;
-  /* If something went wrong, a message indicating what.  */
-  const char *errstr;
 };
 
 /* True for a class member means that it is shared between all objects
@@ -1055,7 +1053,6 @@ lookup_field_r (tree binfo, void *data)
  /* Add the new value.  */
  lfi->ambiguous = tree_cons (NULL_TREE, nval, lfi->ambiguous);
  TREE_TYPE (lfi->ambiguous) = error_mark_node;
- lfi->errstr = G_("request for member %qD is ambiguous");
}
 }
   else
@@ -1127,8 +1124,6 @@ lookup_member (tree xbasetype, tree name, int protect, 
bool want_type,
  checks.  Whereas rval is only set if a proper (not hidden)
  non-function member is found.  */
 
-  const char *errstr = 0;
-
   if (name == error_mark_node
   || xbasetype == NULL_TREE
   || xbasetype == error_mark_node)
@@ -1172,7 +1167,6 @@ lookup_member (tree xbasetype, tree name, int protect, 
bool want_type,
   rval_binfo = lfi.rval_binfo;
   if (rval_binfo)
 type = BINFO_TYPE (rval_binfo);
-  errstr = lfi.errstr;
 
   /* If we are not interested in ambiguities, don't report them;
  just return NULL_TREE.  */
@@ -1187,6 +1181,19 @@ lookup_member (tree xbasetype, tree name, int protect, 
bool want_type,
protect = 0;
 }
 
+  if (protect == 1 && lfi.ambiguous)
+{
+  if (complain & tf_error)
+   {
+ error ("request for member %qD is ambiguous", name);
+ print_candidates (lfi.ambiguous);
+   }
+  return error_mark_node;
+}
+
+  if (!rval)
+return NULL_TREE;
+
   /* [class.access]
 
  In the case of overloaded function names, access control is
@@ -1206,8 +1213,7 @@ lookup_member (tree xbasetype, tree name, int protect, 
bool want_type,
 
 only the first call to "f" is valid.  However, if the function is
 static, we can check.  */
-  if (rval && protect 
-  && !really_overloaded_fn (rval))
+  if (protect && !really_overloaded_fn (rval))
 {
   tree decl = is_overloaded_fn (rval) ? get_first_fn (rval) : rval;
   decl = strip_using_decl (decl);
@@ -1216,21 +1222,10 @@ lookup_member (tree xbasetype, tree name, int protect, 
bool want_type,
  && !DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)
  && !perform_or_defer_access_check (basetype_path, decl, decl,
 complain, afi))
-   rval = error_mark_node;
-}
-
-  if (errstr && protect)
-{
-  if (complain & tf_error)
-   {
- error (errstr, name, type);
- if (lfi.ambiguous)
-   print_candidates (lfi.ambiguous);
-   }
-  rval = error_mark_node;
+   return error_mark_node;
 }
 
-  if (rval && is_overloaded_fn (rval)
+  if (is_overloaded_fn (rval)
   /* Don't use a BASELINK for class-scope deduction guides since
 they're not actually member functions.  */
   && !dguide_name_p (name))
diff --git a/gcc/testsuite/g++.dg/lookup/ambig6.C 
b/gcc/testsuite/g++.dg/lookup/ambig6.C
new file mode 100644
index 000..45e8effba43
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/ambig6.C
@@ -0,0 +1,18 @@
+// PR c++/103177
+
+struct B1 {
+private:
+  static int foo();
+};
+
+struct B2 {
+  int foo();
+};
+
+struct D : B1, B2 { };
+
+void f() {
+  D d;
+  d.foo(); // { dg-error "ambiguous" }
+  // { dg-bogus "private" "" { target *-*-* } .-1 }
+}
-- 
2.35.1.455.g1a4874565f



Re: [PATCH] c++: fold calls to std::move/forward [PR96780]

2022-03-14 Thread Patrick Palka via Gcc-patches
On Fri, 11 Mar 2022, Jason Merrill wrote:

> On 3/10/22 11:27, Patrick Palka wrote:
> > On Wed, 9 Mar 2022, Jason Merrill wrote:
> > 
> > > On 3/1/22 18:08, Patrick Palka wrote:
> > > > A well-formed call to std::move/forward is equivalent to a cast, but the
> > > > former being a function call means it comes with bloated debug info,
> > > > which
> > > > persists even after the call has been inlined away, for an operation
> > > > that
> > > > is never interesting to debug.
> > > > 
> > > > This patch addresses this problem in a relatively ad-hoc way by folding
> > > > calls to std::move/forward into casts as part of the frontend's general
> > > > expression folding routine.  After this patch with -O2 and a
> > > > non-checking
> > > > compiler, debug info size for some testcases decreases by about ~10% and
> > > > overall compile time and memory usage decreases by ~2%.
> > > 
> > > Impressive.  Which testcases?
> > 
> > I saw the largest percent reductions in debug file object size in
> > various tests from cmcstl2 and range-v3, e.g.
> > test/algorithm/set_symmetric_difference4.cpp and .../rotate_copy.cpp
> > (which are among their biggest tests).
> > 
> > Significant reductions in debug object file size can be observed in
> > some libstdc++ testcases too, such as a 5.5% reduction in
> > std/ranges/adaptor/join.cc
> > 
> > > 
> > > Do you also want to handle addressof and as_const in this patch, as
> > > Jonathan
> > > suggested?
> > 
> > Yes, good idea.  Since each of their argument and return types are
> > indirect types, I think we can use the same NOP_EXPR-based folding for
> > them.
> > 
> > > 
> > > I think we can do this now, and think about generalizing more in stage 1.
> > > 
> > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, is this something we
> > > > want to consider for GCC 12?
> > > > 
> > > > PR c++/96780
> > > > 
> > > > gcc/cp/ChangeLog:
> > > > 
> > > > * cp-gimplify.cc (cp_fold) : When optimizing,
> > > > fold calls to std::move/forward into simple casts.
> > > > * cp-tree.h (is_std_move_p, is_std_forward_p): Declare.
> > > > * typeck.cc (is_std_move_p, is_std_forward_p): Export.
> > > > 
> > > > gcc/testsuite/ChangeLog:
> > > > 
> > > > * g++.dg/opt/pr96780.C: New test.
> > > > ---
> > > >gcc/cp/cp-gimplify.cc  | 18 ++
> > > >gcc/cp/cp-tree.h   |  2 ++
> > > >gcc/cp/typeck.cc   |  6 ++
> > > >gcc/testsuite/g++.dg/opt/pr96780.C | 24 
> > > >4 files changed, 46 insertions(+), 4 deletions(-)
> > > >create mode 100644 gcc/testsuite/g++.dg/opt/pr96780.C
> > > > 
> > > > diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
> > > > index d7323fb5c09..0b009b631c7 100644
> > > > --- a/gcc/cp/cp-gimplify.cc
> > > > +++ b/gcc/cp/cp-gimplify.cc
> > > > @@ -2756,6 +2756,24 @@ cp_fold (tree x)
> > > >  case CALL_EXPR:
> > > >  {
> > > > +   if (optimize
> > > 
> > > I think this should check flag_no_inline rather than optimize.
> > 
> > Sounds good.
> > 
> > Here's a patch that extends the folding to as_const and addressof (as
> > well as __addressof, which I'm kind of unsure about since it's
> > non-standard).  I suppose it also doesn't hurt to verify that the return
> > and argument type of the function are sane before we commit to folding.
> > 
> > -- >8 --
> > 
> > Subject: [PATCH] c++: fold calls to std::move/forward [PR96780]
> > 
> > A well-formed call to std::move/forward is equivalent to a cast, but the
> > former being a function call means the compiler generates debug info for
> > it, which persists even after the call has been inlined away, for an
> > operation that's never interesting to debug.
> > 
> > This patch addresses this problem in a relatively ad-hoc way by folding
> > calls to std::move/forward and other cast-like functions into simple
> > casts as part of the frontend's general expression folding routine.
> > After this patch with -O2 and a non-checking compiler, debug info size
> > for some testcases decreases by about ~1

Re: [PATCH] libstdc++: Ensure that std::from_chars is declared when supported

2022-03-14 Thread Patrick Palka via Gcc-patches
On Fri, 11 Mar 2022, Jonathan Wakely wrote:

> Patrick, I think this is right, but please take a look to double check.
> 
> I think we should fix the feature-test macro conditions for gcc-11 too,
> although it's a bit more complicated there. It should depend on IEEE
> float and double *and* uselocale. We don't need the other changes on the
> branch.

Don't we still depend on uselocale in GCC 12 for long double from_chars,
at least on targets where long double != binary64?

> 
> 
> -- >8 --
> 
> This adjusts the declarations in  to match when the definition
> is present. This solves the issue that std::from_chars is present on
> Solaris 11.3 (using fast_float) but was not declared in the header
> (because the declarations were guarded by _GLIBCXX_HAVE_USELOCALE).
> 
> Additionally, do not define __cpp_lib_to_chars unless both from_chars
> and to_chars are supported (which is only true for IEEE float and
> double). We might still provide from_chars (via strtold) but if to_chars
> isn't provided, we shouldn't define the feature test macro.
> 
> Finally, this simplifies some of the preprocessor checks in the bodies
> of std::from_chars in src/c++17/floating_from_chars.cc and hoists the
> repeated code for the strtod version into a new function template.
> 
> libstdc++-v3/ChangeLog:
> 
>   * include/std/charconv (__cpp_lib_to_chars): Only define when
>   both from_chars and to_chars are supported for floating-point
>   types.
>   (from_chars, to_chars): Adjust preprocessor conditions guarding
>   declarations.
>   * include/std/version (__cpp_lib_to_chars): Adjust condition to
>   match  definition.
>   * src/c++17/floating_from_chars.cc (from_chars_strtod): New
>   function template.
>   (from_chars): Simplify preprocessor checks and use
>   from_chars_strtod when appropriate.
> ---
>  libstdc++-v3/include/std/charconv |   8 +-
>  libstdc++-v3/include/std/version  |   3 +-
>  libstdc++-v3/src/c++17/floating_from_chars.cc | 120 ++
>  3 files changed, 45 insertions(+), 86 deletions(-)
> 
> diff --git a/libstdc++-v3/include/std/charconv 
> b/libstdc++-v3/include/std/charconv
> index a3f8c7718b2..2ce9c7d4cb9 100644
> --- a/libstdc++-v3/include/std/charconv
> +++ b/libstdc++-v3/include/std/charconv
> @@ -43,7 +43,8 @@
>  #include  // for std::errc
>  #include 
>  
> -#if _GLIBCXX_HAVE_USELOCALE
> +#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 \
> +&& __SIZE_WIDTH__ >= 32

So ISTM we need to also check

  _GLIBCXX_HAVE_USELOCALE || (__LDBL_MANT_DIG__ == __DBL_MANT_DIG__)

or something like that :/

>  # define __cpp_lib_to_chars 201611L
>  #endif
>  
> @@ -686,7 +687,7 @@ namespace __detail
>operator^=(chars_format& __lhs, chars_format __rhs) noexcept
>{ return __lhs = __lhs ^ __rhs; }
>  
> -#if _GLIBCXX_HAVE_USELOCALE
> +#if defined __cpp_lib_to_chars || _GLIBCXX_HAVE_USELOCALE
>from_chars_result
>from_chars(const char* __first, const char* __last, float& __value,
>chars_format __fmt = chars_format::general) noexcept;
> @@ -700,8 +701,7 @@ namespace __detail
>chars_format __fmt = chars_format::general) noexcept;
>  #endif
>  
> -#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 \
> -&& __SIZE_WIDTH__ >= 32
> +#if defined __cpp_lib_to_chars
>// Floating-point std::to_chars
>  
>// Overloads for float.
> diff --git a/libstdc++-v3/include/std/version 
> b/libstdc++-v3/include/std/version
> index 461e65b5fab..d730a7ea3c7 100644
> --- a/libstdc++-v3/include/std/version
> +++ b/libstdc++-v3/include/std/version
> @@ -171,7 +171,8 @@
>  #endif
>  #define __cpp_lib_shared_ptr_weak_type 201606L
>  #define __cpp_lib_string_view 201803L
> -#if _GLIBCXX_HAVE_USELOCALE
> +#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 \
> +&& __SIZE_WIDTH__ >= 32
>  # define __cpp_lib_to_chars 201611L
>  #endif
>  #define __cpp_lib_unordered_map_try_emplace 201411L
> diff --git a/libstdc++-v3/src/c++17/floating_from_chars.cc 
> b/libstdc++-v3/src/c++17/floating_from_chars.cc
> index ba0426b3344..4aa2483bc28 100644
> --- a/libstdc++-v3/src/c++17/floating_from_chars.cc
> +++ b/libstdc++-v3/src/c++17/floating_from_chars.cc
> @@ -65,6 +65,7 @@ extern "C" __ieee128 __strtoieee128(const char*, char**);
>  && __SIZE_WIDTH__ >= 32
>  # define USE_LIB_FAST_FLOAT 1
>  # if __LDBL_MANT_DIG__ == __DBL_MANT_DIG__
> +// No need to use strtold.
>  #  undef USE_STRTOD_FOR_FROM_CHARS
>  # endif
>  #endif
> @@ -420,6 +421,33 @@ namespace
>  return true;
>}
>  #endif
> +
> +  template
> +  from_chars_result
> +  from_chars_strtod(const char* first, const char* last, T& value,
> + chars_format fmt) noexcept
> +  {
> +errc ec = errc::invalid_argument;
> +#if _GLIBCXX_USE_CXX11_ABI
> +buffer_resource mr;
> +pmr::string buf();
> +#else
> +string buf;
> +if (!reserve_string(buf))
> +  return 

Re: [PATCH] c++: Fix ICE with non-constant satisfaction [PR98644]

2022-03-11 Thread Patrick Palka via Gcc-patches
On Thu, 10 Mar 2022, Jason Merrill wrote:

> On 3/1/22 00:10, Patrick Palka wrote:
> > On Tue, 19 Jan 2021, Jason Merrill wrote:
> > 
> > > On 1/13/21 12:05 PM, Patrick Palka wrote:
> > > > In the below testcase, the expression of the atomic constraint after
> > > > substitution is (int *) NON_LVALUE_EXPR <1> != 0B which is not a C++
> > > > constant expression, but its TREE_CONSTANT flag is set (from build2),
> > > > so satisfy_atom fails to notice that it's non-constant (and we end
> > > > up tripping over the assert in satisfaction_value).
> > > > 
> > > > Since TREE_CONSTANT doesn't necessarily correspond to C++ constantness,
> > > > this patch makes satisfy_atom instead check
> > > > is_rvalue_constant_expression.
> > > > 
> > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > > > trunk/10?
> > > > 
> > > > gcc/cp/ChangeLog:
> > > > 
> > > > PR c++/98644
> > > > * constraint.cc (satisfy_atom): Check 
> > > > is_rvalue_constant_expression
> > > > instead of TREE_CONSTANT.
> > > > 
> > > > gcc/testsuite/ChangeLog:
> > > > 
> > > > PR c++/98644
> > > > * g++.dg/cpp2a/concepts-pr98644.C: New test.
> > > > ---
> > > >gcc/cp/constraint.cc  | 2 +-
> > > >gcc/testsuite/g++.dg/cpp2a/concepts-pr98644.C | 7 +++
> > > >2 files changed, 8 insertions(+), 1 deletion(-)
> > > >create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-pr98644.C
> > > > 
> > > > diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> > > > index 9049d087859..f99a25dc8a4 100644
> > > > --- a/gcc/cp/constraint.cc
> > > > +++ b/gcc/cp/constraint.cc
> > > > @@ -2969,7 +2969,7 @@ satisfy_atom (tree t, tree args, sat_info info)
> > > >{
> > > >  result = maybe_constant_value (result, NULL_TREE,
> > > >  /*manifestly_const_eval=*/true);
> > > > -  if (!TREE_CONSTANT (result))
> > > 
> > > This should be sufficient.  If the result isn't constant,
> > > maybe_constant_value
> > > shouldn't return it with TREE_CONSTANT set.  See
> > > 
> > > >/* This isn't actually constant, so unset TREE_CONSTANT.
> > > 
> > > in cxx_eval_outermost_constant_expr.
> > 
> > I see, so the problem seems to be that the fail-fast path of
> > maybe_constant_value isn't clearing TREE_CONSTANT sufficiently.  Would
> > it make sense to fix this like so?
> > 
> > -- >8 --
> > 
> > Subject: [PATCH] c++: ICE with non-constant satisfaction value [PR98644]
> > 
> > Here during satisfaction the expression of the atomic constraint after
> > substitution is (int *) NON_LVALUE_EXPR <1> != 0B, which is not a C++
> > constant expression due to the reinterpret_cast, but TREE_CONSTANT is
> > set since its value is otherwise effectively constant.  We then call
> > maybe_constant_value on it, which proceeds via its fail-fast path to
> > exit early without clearing TREE_CONSTANT.  But satisfy_atom relies
> > on checking TREE_CONSTANT of the result of maybe_constant_value in order
> > to detect non-constant satisfaction.
> > 
> > This patch fixes this by making the fail-fast path of maybe_constant_value
> > clear TREE_CONSTANT in this case, like cxx_eval_outermost_constant_expr
> > in the normal path would have done.
> > 
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > trunk?
> > 
> > PR c++/98644
> > 
> > gcc/cp/ChangeLog:
> > 
> > * constexpr.cc (maybe_constant_value): In the fail-fast path,
> > clear TREE_CONSTANT on the result if it's set on the input.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/cpp2a/concepts-pr98644.C: New test.
> > * g++.dg/parse/array-size2.C: Remove expected diagnostic about a
> > narrowing conversion.
> > ---
> >   gcc/cp/constexpr.cc   | 4 +++-
> >   gcc/testsuite/g++.dg/cpp2a/concepts-pr98644.C | 7 +++
> >   gcc/testsuite/g++.dg/parse/array-size2.C  | 2 --
> >   3 files changed, 10 insertions(+), 3 deletions(-)
> >   create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-pr98644.C
> > 
> > diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> >

Re: [PATCH] c++: return-type-req in constraint using only outer tparms [PR104527]

2022-03-10 Thread Patrick Palka via Gcc-patches


On Thu, 10 Mar 2022, Jason Merrill wrote:

> On 2/16/22 15:56, Patrick Palka wrote:
> > On Tue, 15 Feb 2022, Jason Merrill wrote:
> > 
> > > On 2/14/22 11:32, Patrick Palka wrote:
> > > > Here the template context for the atomic constraint has two levels of
> > > > template arguments, but since it depends only on the innermost argument
> > > > T we use a single-level argument vector during substitution into the
> > > > constraint (built by get_mapped_args).  We eventually pass this vector
> > > > to do_auto_deduction as part of checking the return-type-requirement
> > > > inside the atom, but do_auto_deduction expects outer_targs to be a full
> > > > set of arguments for sake of satisfaction.
> > > 
> > > Could we note the current number of levels in the map and use that in
> > > get_mapped_args instead of the highest level parameter we happened to use?
> > 
> > Ah yeah, that seems to work nicely.  IIUC it should suffice to remember
> > whether the atomic constraint expression came from a concept definition.
> > If it did, then the depth of the argument vector returned by
> > get_mapped_args must be one, otherwise (as in the testcase) it must be
> > the same as the template depth of the constrained entity, which is the
> > depth of ARGS.
> > 
> > How does the following look?  Bootstrapped and regtested on
> > x86_64-pc-linux-gnu and also on cmcstl2 and range-v3.
> > 
> > -- >8 --
> > 
> > Subject: [PATCH] c++: return-type-req in constraint using only outer tparms
> >   [PR104527]
> > 
> > Here the template context for the atomic constraint has two levels of
> > template parameters, but since it depends only on the innermost parameter
> > T we use a single-level argument vector (built by get_mapped_args) during
> > substitution into the atom.  We eventually pass this vector to
> > do_auto_deduction as part of checking the return-type-requirement within
> > the atom, but do_auto_deduction expects outer_targs to be a full set of
> > arguments for sake of satisfaction.
> > 
> > This patch fixes this by making get_mapped_args always return an
> > argument vector whose depth corresponds to the template depth of the
> > context in which the atomic constraint expression was written, instead
> > of the highest parameter level that the expression happens to use.
> > 
> > PR c++/104527
> > 
> > gcc/cp/ChangeLog:
> > 
> > * constraint.cc (normalize_atom): Set
> > ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P appropriately.
> > (get_mapped_args):  Make static, adjust parameters.  Always
> > return a vector whose depth corresponds to the template depth of
> > the context of the atomic constraint expression.  Micro-optimize
> > by passing false as exact to safe_grow_cleared and by collapsing
> > a multi-level depth-one argument vector.
> > (satisfy_atom): Adjust call to get_mapped_args and
> > diagnose_atomic_constraint.
> > (diagnose_atomic_constraint): Replace map parameter with an args
> > parameter.
> > * cp-tree.h (ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P): Define.
> > (get_mapped_args): Remove declaration.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/cpp2a/concepts-return-req4.C: New test.
> > ---
> >   gcc/cp/constraint.cc  | 64 +++
> >   gcc/cp/cp-tree.h  |  7 +-
> >   .../g++.dg/cpp2a/concepts-return-req4.C   | 24 +++
> >   3 files changed, 69 insertions(+), 26 deletions(-)
> >   create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C
> > 
> > diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> > index 12db7e5cf14..306e28955c6 100644
> > --- a/gcc/cp/constraint.cc
> > +++ b/gcc/cp/constraint.cc
> > @@ -764,6 +764,8 @@ normalize_atom (tree t, tree args, norm_info info)
> > tree ci = build_tree_list (t, info.context);
> >   tree atom = build1 (ATOMIC_CONSTR, ci, map);
> > +  if (info.in_decl && concept_definition_p (info.in_decl))
> > +ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (atom) = true;
> 
> I'm a bit nervous about relying on in_decl, given that we support normalizing
> when it isn't set; I don't remember the circumstances for that.  Maybe make
> the flag indicate that ctx_parms had depth 1?

in_decl gets reliably updated by norm_info::update_context whenever we
recurse inside a concept-id during normalization.  And I think the only
other situation we have to worry about is when starting out with a
concept-i

[PATCH] c++: Fix ICE with bad conversion shortcutting [PR104622]

2022-03-10 Thread Patrick Palka via Gcc-patches
When shortcutting bad conversions during overload resolution, we assume
argument conversions get computed in sequential order and that therefore
we just need to inspect the last conversion in order to determine if _any_
conversion is missing.  But this assumption turns out to be false for
templates, because during deduction check_non_deducible_conversion can
compute an argument conversion out of order.

So in the testcase below, at the end of add_template_candidate the convs
array looks like {bad, missing, good} where the last conversion was
computed during deduction and the first was computed later from
add_function_candidate.  We need to add this candidate to BAD_FNS since
not all of its argument conversions were computed, but we don't do so
because we only checked if the last argument conversion was missing.

This patch fixes this by checking for a missing conversion exhaustively.
In passing, this cleans up check_non_deducible_conversion a bit since
AFAICT the only values of strict we expect to see here are the three
enumerators of unification_kind_t.

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

PR c++/104622

gcc/cp/ChangeLog:

* call.cc (missing_conversion_p): Define.
(add_candidates): Use it.
* pt.cc (check_non_deducible_conversion): Change type of strict
parameter to unification_kind_t and directly test for DEDUCE_CALL.

gcc/testsuite/ChangeLog:

* g++.dg/template/conv18.C: New test.
---
 gcc/cp/call.cc | 13 -
 gcc/cp/pt.cc   |  6 +++---
 gcc/testsuite/g++.dg/template/conv18.C | 14 ++
 3 files changed, 29 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/conv18.C

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index d6eed5ed835..8fe8ef306ea 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -6023,6 +6023,17 @@ perfect_candidate_p (z_candidate *cand)
   return true;
 }
 
+/* True iff one of CAND's argument conversions is NULL.  */
+
+static bool
+missing_conversion_p (const z_candidate *cand)
+{
+  for (unsigned i = 0; i < cand->num_convs; ++i)
+if (!cand->convs[i])
+  return true;
+  return false;
+}
+
 /* Add each of the viable functions in FNS (a FUNCTION_DECL or
OVERLOAD) to the CANDIDATES, returning an updated list of
CANDIDATES.  The ARGS are the arguments provided to the call;
@@ -6200,7 +6211,7 @@ add_candidates (tree fns, tree first_arg, const vec *args,
 
   if (cand->viable == -1
  && shortcut_bad_convs
- && !cand->convs[cand->reversed () ? 0 : cand->num_convs - 1])
+ && missing_conversion_p (cand))
{
  /* This candidate has been tentatively marked non-strictly viable,
 and we didn't compute all argument conversions for it (having
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index f890d92d715..715eea27577 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -152,7 +152,7 @@ static tree coerce_innermost_template_parms (tree, tree, 
tree, tsubst_flags_t,
  bool, bool);
 static void tsubst_enum(tree, tree, tree);
 static bool check_instantiated_args (tree, tree, tsubst_flags_t);
-static int check_non_deducible_conversion (tree, tree, int, int,
+static int check_non_deducible_conversion (tree, tree, unification_kind_t, int,
   struct conversion **, bool);
 static int maybe_adjust_types_for_deduction (tree, unification_kind_t,
 tree*, tree*, tree);
@@ -22304,7 +22304,7 @@ maybe_adjust_types_for_deduction (tree tparms,
unify_one_argument.  */
 
 static int
-check_non_deducible_conversion (tree parm, tree arg, int strict,
+check_non_deducible_conversion (tree parm, tree arg, unification_kind_t strict,
int flags, struct conversion **conv_p,
bool explain_p)
 {
@@ -22324,7 +22324,7 @@ check_non_deducible_conversion (tree parm, tree arg, 
int strict,
   if (can_convert_arg (type, parm, NULL_TREE, flags, complain))
return unify_success (explain_p);
 }
-  else if (strict != DEDUCE_EXACT)
+  else if (strict == DEDUCE_CALL)
 {
   bool ok = false;
   tree conv_arg = TYPE_P (arg) ? NULL_TREE : arg;
diff --git a/gcc/testsuite/g++.dg/template/conv18.C 
b/gcc/testsuite/g++.dg/template/conv18.C
new file mode 100644
index 000..f59f6fda77c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/conv18.C
@@ -0,0 +1,14 @@
+// PR c++/104622
+// { dg-additional-options "-fpermissive" }
+
+template
+struct type_identity {
+  typedef T type;
+};
+
+template void f(typename type_identity::type*, T, int*);
+
+int main() {
+  const int p = 0;
+  f(, 0, 0); // { dg-warning "invalid conversion" }
+}
-- 
2.35.1.455.g1a4874565f



Re: [PATCH] c++: naming a dependently-scoped template for CTAD [PR104641]

2022-03-10 Thread Patrick Palka via Gcc-patches
On Wed, 9 Mar 2022, Jason Merrill wrote:

> On 3/9/22 10:39, Patrick Palka wrote:
> > On Tue, 8 Mar 2022, Jason Merrill wrote:
> > 
> > > On 3/2/22 14:32, Patrick Palka wrote:
> > > > In order to be able to perform CTAD for a dependently-scoped template
> > > > such as A::B in the testcase below, we need to permit a
> > > > typename-specifier to resolve to a template as per [dcl.type.simple]/2,
> > > > at least when it appears in a CTAD-enabled context.
> > > > 
> > > > This patch implements this using a new tsubst flag tf_tst_ok to control
> > > > when a TYPENAME_TYPE is allowed to name a template, and sets this flag
> > > > when substituting into the type of a CAST_EXPR, CONSTRUCTOR or VAR_DECL
> > > > (each of which is a CTAD-enabled context).
> > > 
> > > What breaks if we always allow that, or at least in -std that support
> > > CTAD?
> > 
> > AFAICT no significant breakage, but some accepts-invalid and diagnostic
> > regressions crop up, e.g. accepts-invalid for
> > 
> >using type = typename A::B; // no more diagnostic if typename resolves
> > to a
> >   // template at instantiation time
> > 
> > and diagnostic regression for
> > 
> >template::B> void f();
> >// no more elaboration why deduction failed if typename resolves
> >// to a template
> 
> Ah, sure, the cost is that we would need to check for this case in various
> callers, rather than setting a flag in a different set of callers.  Fair
> enough.

Yes exactly, and presumably the set of callers for which typename is
permitted to resolve to a template is much smaller, so making the
behavior opt-in instead of opt-out seems more desirable.  Alternatively
we could add a new flag to TYPENAME_TYPE set carefully at parse time
that controls this behavior, but seems overall simpler to not use a
new tree flag if we can get away with it.

> 
> > @@ -16229,6 +16237,12 @@ tsubst (tree t, tree args, tsubst_flags_t complain,
> > tree in_decl)
> >   }
> >   }
> >  +  if (TREE_CODE (f) == TEMPLATE_DECL)
> > + {
> > +   gcc_checking_assert (tst_ok);
> > +   f = make_template_placeholder (f);
> > + }
> 
> How about calling make_template_placeholder in make_typename_type?

That works nicely too, like so?

-- >8 --

Subject: [PATCH] c++: naming a dependently-scoped template for CTAD [PR104641]

In order to be able to perform CTAD for a dependently-scoped template
(such as A::B in the testcase below), we need to permit a
typename-specifier to resolve to a template as per [dcl.type.simple]/3,
at least when it appears in a CTAD-enabled context.

This patch implements this using a new tsubst flag tf_tst_ok to control
when a TYPENAME_TYPE is allowed to name a template, and sets this flag
when substituting into the type of a CAST_EXPR, CONSTRUCTOR or VAR_DECL
(each of which is a CTAD-enabled context).

PR c++/104641

gcc/cp/ChangeLog:

* cp-tree.h (tsubst_flags::tf_tst_ok): New flag.
* decl.cc (make_typename_type): Allow a typename-specifier to
resolve to a template when tf_tst_ok, in which case return
a CTAD placeholder for the template.
* pt.cc (tsubst_decl) : Set tf_tst_ok when
substituting the type.
(tsubst): Clear tf_tst_ok and remember if it was set.
: Pass tf_tst_ok to make_typename_type
appropriately.
(tsubst_copy) : Set tf_tst_ok when substituting
the type.
(tsubst_copy_and_build) : Likewise.
: Likewise.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/class-deduction107.C: New test.
---
 gcc/cp/cp-tree.h  |  2 ++
 gcc/cp/decl.cc| 20 ++---
 gcc/cp/pt.cc  | 29 +++
 .../g++.dg/cpp1z/class-deduction107.C | 20 +
 4 files changed, 61 insertions(+), 10 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction107.C

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index b71bce1ab97..b7606f22287 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5557,6 +5557,8 @@ enum tsubst_flags {
(build_target_expr and friends) */
   tf_norm = 1 << 11,/* Build diagnostic information during
constraint normalization.  */
+  tf_tst_ok = 1 << 12,  /* Allow a typename-specifier to name
+   a template.  */
   /* Convenient substitution flags combinations.  */
   tf_warning_or_error = tf_warning | tf_error
 };
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 992e38385c2..d2d46915068 100644
--- a

Re: [PATCH] c++: fold calls to std::move/forward [PR96780]

2022-03-10 Thread Patrick Palka via Gcc-patches
On Wed, 9 Mar 2022, Jason Merrill wrote:

> On 3/1/22 18:08, Patrick Palka wrote:
> > A well-formed call to std::move/forward is equivalent to a cast, but the
> > former being a function call means it comes with bloated debug info, which
> > persists even after the call has been inlined away, for an operation that
> > is never interesting to debug.
> > 
> > This patch addresses this problem in a relatively ad-hoc way by folding
> > calls to std::move/forward into casts as part of the frontend's general
> > expression folding routine.  After this patch with -O2 and a non-checking
> > compiler, debug info size for some testcases decreases by about ~10% and
> > overall compile time and memory usage decreases by ~2%.
> 
> Impressive.  Which testcases?

I saw the largest percent reductions in debug file object size in
various tests from cmcstl2 and range-v3, e.g.
test/algorithm/set_symmetric_difference4.cpp and .../rotate_copy.cpp
(which are among their biggest tests).

Significant reductions in debug object file size can be observed in
some libstdc++ testcases too, such as a 5.5% reduction in
std/ranges/adaptor/join.cc

> 
> Do you also want to handle addressof and as_const in this patch, as Jonathan
> suggested?

Yes, good idea.  Since each of their argument and return types are
indirect types, I think we can use the same NOP_EXPR-based folding for
them.

> 
> I think we can do this now, and think about generalizing more in stage 1.
> 
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, is this something we
> > want to consider for GCC 12?
> > 
> > PR c++/96780
> > 
> > gcc/cp/ChangeLog:
> > 
> > * cp-gimplify.cc (cp_fold) : When optimizing,
> > fold calls to std::move/forward into simple casts.
> > * cp-tree.h (is_std_move_p, is_std_forward_p): Declare.
> > * typeck.cc (is_std_move_p, is_std_forward_p): Export.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/opt/pr96780.C: New test.
> > ---
> >   gcc/cp/cp-gimplify.cc  | 18 ++
> >   gcc/cp/cp-tree.h   |  2 ++
> >   gcc/cp/typeck.cc   |  6 ++
> >   gcc/testsuite/g++.dg/opt/pr96780.C | 24 
> >   4 files changed, 46 insertions(+), 4 deletions(-)
> >   create mode 100644 gcc/testsuite/g++.dg/opt/pr96780.C
> > 
> > diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
> > index d7323fb5c09..0b009b631c7 100644
> > --- a/gcc/cp/cp-gimplify.cc
> > +++ b/gcc/cp/cp-gimplify.cc
> > @@ -2756,6 +2756,24 @@ cp_fold (tree x)
> > case CALL_EXPR:
> > {
> > +   if (optimize
> 
> I think this should check flag_no_inline rather than optimize.

Sounds good.

Here's a patch that extends the folding to as_const and addressof (as
well as __addressof, which I'm kind of unsure about since it's
non-standard).  I suppose it also doesn't hurt to verify that the return
and argument type of the function are sane before we commit to folding.

-- >8 --

Subject: [PATCH] c++: fold calls to std::move/forward [PR96780]

A well-formed call to std::move/forward is equivalent to a cast, but the
former being a function call means the compiler generates debug info for
it, which persists even after the call has been inlined away, for an
operation that's never interesting to debug.

This patch addresses this problem in a relatively ad-hoc way by folding
calls to std::move/forward and other cast-like functions into simple
casts as part of the frontend's general expression folding routine.
After this patch with -O2 and a non-checking compiler, debug info size
for some testcases decreases by about ~10% and overall compile time and
memory usage decreases by ~2%.

PR c++/96780

gcc/cp/ChangeLog:

* cp-gimplify.cc (cp_fold) : When optimizing,
fold calls to std::move/forward and other cast-like functions
into simple casts.

gcc/testsuite/ChangeLog:

* g++.dg/opt/pr96780.C: New test.
---
 gcc/cp/cp-gimplify.cc  | 36 +++-
 gcc/testsuite/g++.dg/opt/pr96780.C | 38 ++
 2 files changed, 73 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/opt/pr96780.C

diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
index d7323fb5c09..efc4c8f0eb9 100644
--- a/gcc/cp/cp-gimplify.cc
+++ b/gcc/cp/cp-gimplify.cc
@@ -2756,9 +2756,43 @@ cp_fold (tree x)
 
 case CALL_EXPR:
   {
-   int sv = optimize, nw = sv;
tree callee = get_callee_fndecl (x);
 
+   /* "Inline" calls to std::move/forward and other cast-like functions
+  by simply folding them into the corresponding cast determined by
+  their return type.  This is cheaper t

[committed] libstdc++: Avoid implicit narrowing from uint128_t [PR104859]

2022-03-09 Thread Patrick Palka via Gcc-patches
We need to be explicit about narrowing conversions from uint128_t since,
on targets that lack __int128, this type is defined as an integer-class
type that is only _explicitly_ convertible to the builtin integer types.
This issue was latent until r12-7563-ge32869a17b788b made the frontend
correctly reject explicit conversion functions during (dependent)
copy-initialization.

Tested on x86_64-pc-linux-gnu using both possible definitions of uint128
(as an alias for unsigned __int128 and as the integer-class type), committed to
trunk as obvious.

PR libstdc++/104859

libstdc++-v3/ChangeLog:

* src/c++17/floating_to_chars.cc (__floating_to_chars_hex):
Be explicit when narrowing the shifted effective_mantissa,
since it may have an integer-class type.
---
 libstdc++-v3/src/c++17/floating_to_chars.cc | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/libstdc++-v3/src/c++17/floating_to_chars.cc 
b/libstdc++-v3/src/c++17/floating_to_chars.cc
index 5825e661bf4..66bd457cbe2 100644
--- a/libstdc++-v3/src/c++17/floating_to_chars.cc
+++ b/libstdc++-v3/src/c++17/floating_to_chars.cc
@@ -801,14 +801,14 @@ template
 char leading_hexit;
 if constexpr (has_implicit_leading_bit)
   {
-   const unsigned nibble = effective_mantissa >> rounded_mantissa_bits;
+   const auto nibble = unsigned(effective_mantissa >> 
rounded_mantissa_bits);
__glibcxx_assert(nibble <= 2);
leading_hexit = '0' + nibble;
effective_mantissa &= ~(mantissa_t{0b11} << rounded_mantissa_bits);
   }
 else
   {
-   const unsigned nibble = effective_mantissa >> (rounded_mantissa_bits-4);
+   const auto nibble = unsigned(effective_mantissa >> 
(rounded_mantissa_bits-4));
__glibcxx_assert(nibble < 16);
leading_hexit = "0123456789abcdef"[nibble];
effective_mantissa &= ~(mantissa_t{0b} << 
(rounded_mantissa_bits-4));
@@ -853,7 +853,7 @@ template
while (effective_mantissa != 0)
  {
nibble_offset -= 4;
-   const unsigned nibble = effective_mantissa >> nibble_offset;
+   const auto nibble = unsigned(effective_mantissa >> nibble_offset);
__glibcxx_assert(nibble < 16);
*first++ = "0123456789abcdef"[nibble];
++written_hexits;
-- 
2.35.1.415.gc2162907e9



Re: [PATCH] contrib: Fix non-portable sed commands in gcc-descr [PR102664/]

2022-03-09 Thread Patrick Palka via Gcc-patches
On Wed, Mar 9, 2022 at 8:54 AM Mikael Morin  wrote:
>
> Hello,
>
> Le 08/03/2022 à 18:58, Jonathan Wakely via Gcc-patches a écrit :
> > Replace \([0-9]\+\) with \([0-9][0-9]*\) or with \([1-9][0-9]*\) in release 
> > branch numbers, where
> > a leading zero does not occur.
> >
> Note that you also changed some gcc-[0-9]* to gcc-[1-9]*, which is a
> typo/thinko I guess?  It looks like it wouldn’t match gcc-10 any more
> for example…

Perhaps related to this, I noticed the following
  git gcc-descr ea1ce0d163ea1d63b6837144ae4be51d92630007
now fails with
  fatal: No tags can describe 'ea1ce0d163ea1d63b6837144ae4be51d92630007'.
instead of outputting
  r0-52309-gea1ce0d163ea1d

>
> > diff --git a/contrib/git-descr.sh b/contrib/git-descr.sh
> > index ba5d711f330..95363279d8c 100755
> > --- a/contrib/git-descr.sh
> > +++ b/contrib/git-descr.sh
> > @@ -18,11 +18,11 @@ do
> >   done
> >
> >   if test x$short = xyes; then
> > -r=$(git describe --all --match 'basepoints/gcc-[0-9]*' $c | sed -n 
> > 's,^\(tags/\)\?basepoints/gcc-\([0-9]\+\)-\([0-9]\+\)-g[0-9a-f]*$,r\2-\3,p;s,^\(tags/\)\?basepoints/gcc-\([0-9]\+\)$,r\2-0,p');
> > +r=$(git describe --all --match 'basepoints/gcc-[1-9]*' $c | sed -n 
> > 's,^tags/,,;s,^basepoints/gcc-\([1-9][0-9]*\)-\([0-9][0-9]*\)-g[0-9a-f]*$,r\1-\2,p;s,^basepoints/gcc-\([1-9][0-9]*\)$,r\1-0,p');
>
> …here…
>
> >   elif test x$long = xyes; then
> > -r=$(git describe --all --abbrev=40 --match 'basepoints/gcc-[0-9]*' $c 
> > | sed -n 's,^\(tags/\)\?basepoints/gcc-,r,p')
> > +r=$(git describe --all --abbrev=40 --match 'basepoints/gcc-[1-9]*' $c 
> > | sed -n 's,^tags/,,;s,^basepoints/gcc-,r,p')
>
> … and here …
>
> >   else
> > -r=$(git describe --all --abbrev=14 --match 'basepoints/gcc-[0-9]*' $c 
> > | sed -n 's,^\(tags/\)\?basepoints/gcc-,r,p');
> > +r=$(git describe --all --abbrev=14 --match 'basepoints/gcc-[1-9]*' $c 
> > | sed -n 's,^tags/,,;s,^basepoints/gcc-,r,p')
>
> … and here.
>



Re: [PATCH] c++: naming a dependently-scoped template for CTAD [PR104641]

2022-03-09 Thread Patrick Palka via Gcc-patches
On Tue, 8 Mar 2022, Jason Merrill wrote:

> On 3/2/22 14:32, Patrick Palka wrote:
> > In order to be able to perform CTAD for a dependently-scoped template
> > such as A::B in the testcase below, we need to permit a
> > typename-specifier to resolve to a template as per [dcl.type.simple]/2,
> > at least when it appears in a CTAD-enabled context.
> > 
> > This patch implements this using a new tsubst flag tf_tst_ok to control
> > when a TYPENAME_TYPE is allowed to name a template, and sets this flag
> > when substituting into the type of a CAST_EXPR, CONSTRUCTOR or VAR_DECL
> > (each of which is a CTAD-enabled context).
> 
> What breaks if we always allow that, or at least in -std that support CTAD?

AFAICT no significant breakage, but some accepts-invalid and diagnostic
regressions crop up, e.g. accepts-invalid for

  using type = typename A::B; // no more diagnostic if typename resolves to a
 // template at instantiation time

and diagnostic regression for

  template::B> void f();
  // no more elaboration why deduction failed if typename resolves
  // to a template



Re: [PATCH] c++: detecting copy-init context during CTAD [PR102137]

2022-03-08 Thread Patrick Palka via Gcc-patches
On Tue, 8 Mar 2022, Jason Merrill wrote:

> On 3/8/22 14:38, Patrick Palka wrote:
> > On Tue, 8 Mar 2022, Jason Merrill wrote:
> > 
> > > On 3/8/22 11:36, Patrick Palka wrote:
> > > > On Mon, 7 Mar 2022, Jason Merrill wrote:
> > > > 
> > > > > On 3/7/22 10:47, Patrick Palka wrote:
> > > > > > On Fri, 4 Mar 2022, Jason Merrill wrote:
> > > > > > 
> > > > > > > On 3/4/22 14:24, Patrick Palka wrote:
> > > > > > > > Here we're failing to communicate to cp_finish_decl from
> > > > > > > > tsubst_expr
> > > > > > > > that we're in a copy-initialization context (via the
> > > > > > > > LOOKUP_ONLYCONVERTING
> > > > > > > > flag), which causes do_class_deduction to always consider
> > > > > > > > explicit
> > > > > > > > deduction guides when performing CTAD for a templated variable
> > > > > > > > initializer.
> > > > > > > > 
> > > > > > > > We could fix this by passing LOOKUP_ONLYCONVERTING appropriately
> > > > > > > > when
> > > > > > > > calling cp_finish_decl from tsubst_expr, but it seems
> > > > > > > > do_class_deduction
> > > > > > > > can determine if we're in a copy-init context by simply
> > > > > > > > inspecting
> > > > > > > > the
> > > > > > > > initializer, and thus render its flags parameter unnecessary,
> > > > > > > > which
> > > > > > > > is
> > > > > > > > what this patch implements.  (If we were to fix this in
> > > > > > > > tsubst_expr
> > > > > > > > instead, I think we'd have to inspect the initializer in the
> > > > > > > > same
> > > > > > > > way
> > > > > > > > in order to detect a copy-init context?)
> > > > > > > 
> > > > > > > Hmm, does this affect conversions as well?
> > > > > > > 
> > > > > > > Looks like it does:
> > > > > > > 
> > > > > > > struct A
> > > > > > > {
> > > > > > >  explicit operator int();
> > > > > > > };
> > > > > > > 
> > > > > > > template  void f()
> > > > > > > {
> > > > > > >  T t = A();
> > > > > > > }
> > > > > > > 
> > > > > > > int main()
> > > > > > > {
> > > > > > >  f(); // wrongly accepted
> > > > > > > }
> > > > > > > 
> > > > > > > The reverse, initializing via an explicit constructor, is caught
> > > > > > > by
> > > > > > > code
> > > > > > > in
> > > > > > > build_aggr_init much like the code your patch adds to
> > > > > > > do_auto_deduction;
> > > > > > > perhaps we should move/copy that code to cp_finish_decl?
> > > > > > 
> > > > > > Ah, makes sense.  Moving that code from build_aggr_init to
> > > > > > cp_finish_decl broke things, but using it in both spots seems to
> > > > > > work
> > > > > > well.  And I suppose we might as well use it in do_class_deduction
> > > > > > too,
> > > > > > since doing so lets us remove the flags parameter.
> > > > > 
> > > > > Before removing the flags parameter please try asserting that it now
> > > > > matches
> > > > > is_copy_initialization and see if anything breaks.
> > > > 
> > > > I added to do_class_deduction:
> > > > 
> > > > gcc_assert (bool(flags & LOOKUP_ONLYCONVERTING) ==
> > > > is_copy_initialization
> > > > (init));
> > > > 
> > > > Turns out removing the flags parameter breaks CTAD for new-expressions
> > > > of the form 'new TT(x)' because in this case build_new passes just 'x'
> > > > as the initializer to do_auto_deduction (as opposed to a single
> > > > TREE_LIST),
> > > > for which is_copy_initialization returns true even though it's really
> > > > direct

Re: [PATCH] c++: non-constant non-dependent decltype folding [PR104823]

2022-03-08 Thread Patrick Palka via Gcc-patches
On Tue, 8 Mar 2022, Jason Merrill wrote:

> On 3/8/22 12:54, Patrick Palka wrote:
> > 
> > 
> > On Mon, 7 Mar 2022, Jason Merrill wrote:
> > 
> > > On 3/7/22 14:41, Patrick Palka wrote:
> > > > instantiate_non_dependent_expr_sfinae instantiates only potentially
> > > > constant expressions
> > > 
> > > Hmm, that now strikes me as a problematic interface, as we don't know
> > > whether
> > > what we get back is template or non-template trees.
> > > 
> > > Maybe we want to change instantiate_non_dependent_expr to checking_assert
> > > that
> > > the argument is non-dependent (callers are already checking that), and
> > > drop
> > > the potentially-constant test?
> > 
> > That sounds like a nice improvement.  But it happens to break
> > 
> >template using type = decltype(N);
> > 
> > beause finish_decltype_type checks
> > instantiation_dependent_uneval_expression_p
> > (which is false here) instead of instantiation_dependent_expression_p
> > (which is true here) before calling instantiate_non_dependent_expr, so
> > we end up tripping over the proposed checking_assert (which checks the
> > latter stronger form of dependence).
> > 
> > I suspect other callers of instantiate_non_dependent_expr might have a
> > similar problem if they use a weaker dependence check than
> > instantiation_dependent_expression_p, e.g. build_noexcept_spec only
> > checks value_dependent_expression_p.
> > 
> > I wonder if we should relax the proposed checking_assert in i_n_d_e, or
> > strengthen the dependence checks performed by its callers, or something
> > else?
> 
> I think relax the assert to _uneval and strengthen callers that use value_dep.

Sounds good, like so?  Note this patch doesn't touch
instantiate_non_dependent_or_null or fold_non_dependent_expr, since the
former already never returns a templated tree, and callers of the latter
should only care about the constant-ness not template-ness of the result
IIUC.

Boostrapped and regtested on x86_64-pc-linux-gnu.

-- >8 --

Subject: [PATCH] c++: non-constant non-dependent decltype folding [PR104823]

When processing a non-dependent decltype operand we want to instantiate
it even if it's non-constant since non-dependent decltype is always
resolved ahead of time.  But currently finish_decltype_type uses
instantiate_non_dependent_expr, which instantiates only potentially
constant expressions, and this causes us to miss diagnosing the narrowing
conversion in S{id(v)} in the below testcase because we never instantiate
this non-constant non-dependent decltype operand.

In light of

  > On Mon, 7 Mar 2022, Jason Merrill wrote:
  >> On 3/7/22 14:41, Patrick Palka wrote:
  >>> instantiate_non_dependent_expr instantiates only potentially constant
  >>> expressions
  >>
  >> Hmm, that now strikes me as a problematic interface, as we don't know 
whether
  >> what we get back is template or non-template trees.

this patch drops the potentially-constant check in i_n_d_e, and turns
its dependence check into a checking_assert, since most callers already
check that the argument is non-dependent.  This patch also relaxes the
dependence check in i_n_d_e to use the _uneval version and strengthens
the dependence checks used by callers accordingly.

In cp_parser_parenthesized_expression_list_elt we were calling
instantiate_non_dependent_expr without first checking for non-dependence.
We could fix this by guarding the call appropriately, but I noticed we
also fold non-dependent attributes later from cp_check_const_attribute.
This double instantiation causes us to reject constexpr-attribute4.C
below due to the second folding seeing non-templated trees (an existing
bug).  Thus the right solution here seems to be to remove this unguarded
call to i_n_d_e so that we end up folding non-dependent attributes only
once.

Finally, after calling i_n_d_e in finish_decltype_type we need to keep
processing_template_decl cleared for sake of the later call to
lvalue_kind, which handles templated and non-templated COND_EXPR
differently.  Otherwise we'd incorrectly reject the declaration of g in
cpp0x/cond2.C with:

  error: 'g' declared as function returning a function

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

PR c++/104823

gcc/cp/ChangeLog:

* except.cc (build_noexcept_spec): Strengthen dependence check
to instantiation_dependent_expression_p.
* parser.cc (cp_parser_parenthesized_expression_list_elt):
Remove fold_expr_p parameter and call
instantiate_non_dependent_expr.
(cp_parser_parenthesized_expression_list): Adjust accordingly.
* pt.cc (expand_integer_pa

Re: [PATCH] c++: detecting copy-init context during CTAD [PR102137]

2022-03-08 Thread Patrick Palka via Gcc-patches
On Tue, 8 Mar 2022, Jason Merrill wrote:

> On 3/8/22 11:36, Patrick Palka wrote:
> > On Mon, 7 Mar 2022, Jason Merrill wrote:
> > 
> > > On 3/7/22 10:47, Patrick Palka wrote:
> > > > On Fri, 4 Mar 2022, Jason Merrill wrote:
> > > > 
> > > > > On 3/4/22 14:24, Patrick Palka wrote:
> > > > > > Here we're failing to communicate to cp_finish_decl from tsubst_expr
> > > > > > that we're in a copy-initialization context (via the
> > > > > > LOOKUP_ONLYCONVERTING
> > > > > > flag), which causes do_class_deduction to always consider explicit
> > > > > > deduction guides when performing CTAD for a templated variable
> > > > > > initializer.
> > > > > > 
> > > > > > We could fix this by passing LOOKUP_ONLYCONVERTING appropriately
> > > > > > when
> > > > > > calling cp_finish_decl from tsubst_expr, but it seems
> > > > > > do_class_deduction
> > > > > > can determine if we're in a copy-init context by simply inspecting
> > > > > > the
> > > > > > initializer, and thus render its flags parameter unnecessary, which
> > > > > > is
> > > > > > what this patch implements.  (If we were to fix this in tsubst_expr
> > > > > > instead, I think we'd have to inspect the initializer in the same
> > > > > > way
> > > > > > in order to detect a copy-init context?)
> > > > > 
> > > > > Hmm, does this affect conversions as well?
> > > > > 
> > > > > Looks like it does:
> > > > > 
> > > > > struct A
> > > > > {
> > > > > explicit operator int();
> > > > > };
> > > > > 
> > > > > template  void f()
> > > > > {
> > > > > T t = A();
> > > > > }
> > > > > 
> > > > > int main()
> > > > > {
> > > > > f(); // wrongly accepted
> > > > > }
> > > > > 
> > > > > The reverse, initializing via an explicit constructor, is caught by
> > > > > code
> > > > > in
> > > > > build_aggr_init much like the code your patch adds to
> > > > > do_auto_deduction;
> > > > > perhaps we should move/copy that code to cp_finish_decl?
> > > > 
> > > > Ah, makes sense.  Moving that code from build_aggr_init to
> > > > cp_finish_decl broke things, but using it in both spots seems to work
> > > > well.  And I suppose we might as well use it in do_class_deduction too,
> > > > since doing so lets us remove the flags parameter.
> > > 
> > > Before removing the flags parameter please try asserting that it now
> > > matches
> > > is_copy_initialization and see if anything breaks.
> > 
> > I added to do_class_deduction:
> > 
> >gcc_assert (bool(flags & LOOKUP_ONLYCONVERTING) == is_copy_initialization
> > (init));
> > 
> > Turns out removing the flags parameter breaks CTAD for new-expressions
> > of the form 'new TT(x)' because in this case build_new passes just 'x'
> > as the initializer to do_auto_deduction (as opposed to a single TREE_LIST),
> > for which is_copy_initialization returns true even though it's really
> > direct initalization.
> > 
> > Also turns out we're similarly not passing the right LOOKUP_* flags to
> > cp_finish_decl from instantiate_body, which breaks consideration of
> > explicit conversions/deduction guides when instantiating the initializer
> > of a static data member.  I added some xfailed testcases for these
> > situations.
> 
> Maybe we want to check is_copy_initialization in cp_finish_decl?

That seems to work nicely :) All xfailed tests for the static data
member initialization case now also pass.

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

-- >8 --

Subject: [PATCH] c++: detecting copy-init context during CTAD [PR102137]

Here we're failing to communicate to cp_finish_decl from tsubst_expr
that we're in a copy-initialization context (via the LOOKUP_ONLYCONVERTING
flag), which causes us to always consider explicit deduction guides when
performing CTAD for a templated variable initializer.

It turns out this bug also affects consideration of explicit conversion
operators for the same reason.  But consideration of explicit constructors
seems to do the right thing thanks to code in build_aggr_

Re: [PATCH] c++: non-constant non-dependent decltype folding [PR104823]

2022-03-08 Thread Patrick Palka via Gcc-patches



On Mon, 7 Mar 2022, Jason Merrill wrote:

> On 3/7/22 14:41, Patrick Palka wrote:
> > instantiate_non_dependent_expr_sfinae instantiates only potentially
> > constant expressions
> 
> Hmm, that now strikes me as a problematic interface, as we don't know whether
> what we get back is template or non-template trees.
> 
> Maybe we want to change instantiate_non_dependent_expr to checking_assert that
> the argument is non-dependent (callers are already checking that), and drop
> the potentially-constant test?

That sounds like a nice improvement.  But it happens to break

  template using type = decltype(N);

beause finish_decltype_type checks instantiation_dependent_uneval_expression_p
(which is false here) instead of instantiation_dependent_expression_p
(which is true here) before calling instantiate_non_dependent_expr, so
we end up tripping over the proposed checking_assert (which checks the
latter stronger form of dependence).

I suspect other callers of instantiate_non_dependent_expr might have a
similar problem if they use a weaker dependence check than
instantiation_dependent_expression_p, e.g. build_noexcept_spec only
checks value_dependent_expression_p.

I wonder if we should relax the proposed checking_assert in i_n_d_e, or
strengthen the dependence checks performed by its callers, or something
else?

Here's the diff I'm working with:

-- >8 --

 gcc/cp/parser.cc|  2 +-
 gcc/cp/pt.cc| 21 ++---
 gcc/cp/semantics.cc | 11 ---
 3 files changed, 11 insertions(+), 23 deletions(-)

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 20aab5eb6b1..a570a9163b9 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -7986,7 +7986,7 @@ cp_parser_parenthesized_expression_list_elt (cp_parser 
*parser, bool cast_p,
 expr = cp_parser_assignment_expression (parser, /*pidk=*/NULL, cast_p);
 
   if (fold_expr_p)
-expr = instantiate_non_dependent_expr (expr);
+expr = fold_non_dependent_expr (expr);
 
   /* If we have an ellipsis, then this is an expression expansion.  */
   if (allow_expansion_p
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 53a74636279..1b2d9a7e4b1 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -6350,8 +6350,7 @@ redeclare_class_template (tree type, tree parms, tree 
cons)
 /* The actual substitution part of instantiate_non_dependent_expr_sfinae,
to be used when the caller has already checked
(processing_template_decl
-&& !instantiation_dependent_expression_p (expr)
-&& potential_constant_expression (expr))
+&& !instantiation_dependent_expression_p (expr))
and cleared processing_template_decl.  */
 
 tree
@@ -6365,8 +6364,7 @@ instantiate_non_dependent_expr_internal (tree expr, 
tsubst_flags_t complain)
/*integral_constant_expression_p=*/true);
 }
 
-/* Simplify EXPR if it is a non-dependent expression.  Returns the
-   (possibly simplified) expression.  */
+/* Instantiate the non-dependent expression EXPR.  */
 
 tree
 instantiate_non_dependent_expr_sfinae (tree expr, tsubst_flags_t complain)
@@ -6374,16 +6372,9 @@ instantiate_non_dependent_expr_sfinae (tree expr, 
tsubst_flags_t complain)
   if (expr == NULL_TREE)
 return NULL_TREE;
 
-  /* If we're in a template, but EXPR isn't value dependent, simplify
- it.  We're supposed to treat:
-
-   template  void f(T[1 + 1]);
-   template  void f(T[2]);
-
- as two declarations of the same function, for example.  */
-  if (processing_template_decl
-  && is_nondependent_constant_expression (expr))
+  if (processing_template_decl)
 {
+  gcc_checking_assert (!instantiation_dependent_expression_p (expr));
   processing_template_decl_sentinel s;
   expr = instantiate_non_dependent_expr_internal (expr, complain);
 }
@@ -6396,8 +6387,8 @@ instantiate_non_dependent_expr (tree expr)
   return instantiate_non_dependent_expr_sfinae (expr, tf_error);
 }
 
-/* Like instantiate_non_dependent_expr, but return NULL_TREE rather than
-   an uninstantiated expression.  */
+/* Like instantiate_non_dependent_expr, but return NULL_TREE if the
+   expression is dependent or non-constant.  */
 
 tree
 instantiate_non_dependent_or_null (tree expr)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 66d90c2f7be..8f744eb21b6 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -11234,16 +11234,13 @@ finish_decltype_type (tree expr, bool 
id_expression_or_member_access_p,
 }
   else if (processing_template_decl)
 {
-  /* Instantiate the non-dependent operand to diagnose any ill-formed
-expressions.  And keep processing_template_decl cleared for the rest
+  expr = instantiate_non_dependent_expr_sfinae (expr, complain);
+  if (expr == error_mark_node)
+   return error_mark_node;
+  /* Keep processing_template_decl cleared for the rest
 of the function (for sake of the call to lvalue_kind below, w

Re: [PATCH] c++: detecting copy-init context during CTAD [PR102137]

2022-03-08 Thread Patrick Palka via Gcc-patches
On Mon, 7 Mar 2022, Jason Merrill wrote:

> On 3/7/22 10:47, Patrick Palka wrote:
> > On Fri, 4 Mar 2022, Jason Merrill wrote:
> > 
> > > On 3/4/22 14:24, Patrick Palka wrote:
> > > > Here we're failing to communicate to cp_finish_decl from tsubst_expr
> > > > that we're in a copy-initialization context (via the
> > > > LOOKUP_ONLYCONVERTING
> > > > flag), which causes do_class_deduction to always consider explicit
> > > > deduction guides when performing CTAD for a templated variable
> > > > initializer.
> > > > 
> > > > We could fix this by passing LOOKUP_ONLYCONVERTING appropriately when
> > > > calling cp_finish_decl from tsubst_expr, but it seems do_class_deduction
> > > > can determine if we're in a copy-init context by simply inspecting the
> > > > initializer, and thus render its flags parameter unnecessary, which is
> > > > what this patch implements.  (If we were to fix this in tsubst_expr
> > > > instead, I think we'd have to inspect the initializer in the same way
> > > > in order to detect a copy-init context?)
> > > 
> > > Hmm, does this affect conversions as well?
> > > 
> > > Looks like it does:
> > > 
> > > struct A
> > > {
> > >explicit operator int();
> > > };
> > > 
> > > template  void f()
> > > {
> > >T t = A();
> > > }
> > > 
> > > int main()
> > > {
> > >f(); // wrongly accepted
> > > }
> > > 
> > > The reverse, initializing via an explicit constructor, is caught by code
> > > in
> > > build_aggr_init much like the code your patch adds to do_auto_deduction;
> > > perhaps we should move/copy that code to cp_finish_decl?
> > 
> > Ah, makes sense.  Moving that code from build_aggr_init to
> > cp_finish_decl broke things, but using it in both spots seems to work
> > well.  And I suppose we might as well use it in do_class_deduction too,
> > since doing so lets us remove the flags parameter.
> 
> Before removing the flags parameter please try asserting that it now matches
> is_copy_initialization and see if anything breaks.

I added to do_class_deduction:

  gcc_assert (bool(flags & LOOKUP_ONLYCONVERTING) == is_copy_initialization 
(init));

Turns out removing the flags parameter breaks CTAD for new-expressions
of the form 'new TT(x)' because in this case build_new passes just 'x'
as the initializer to do_auto_deduction (as opposed to a single TREE_LIST),
for which is_copy_initialization returns true even though it's really
direct initalization.

Also turns out we're similarly not passing the right LOOKUP_* flags to
cp_finish_decl from instantiate_body, which breaks consideration of
explicit conversions/deduction guides when instantiating the initializer
of a static data member.  I added some xfailed testcases for these
situations.

Here's a patch that keeps the flags parameter of do_auto_deduction, and
only changes the call to cp_finish_decl from tsubst_expr:

-- >8 --

Subject: [PATCH] c++: detecting copy-init context during CTAD [PR102137]

Here we're failing to communicate to cp_finish_decl from tsubst_expr
that we're in a copy-initialization context (via the LOOKUP_ONLYCONVERTING
flag), which causes us to always consider explicit deduction guides when
performing CTAD for a templated variable initializer.

It turns out this bug also affects consideration of explicit conversion
operators for the same reason.  But consideration of explicit constructors
is unaffected and seems to work correctly thanks to code in build_aggr_init
that sets LOOKUP_ONLYCONVERTING when the initializer represents
copy-initialization.

This patch factors out the copy-initialization check from build_aggr_init
and reuses it in tsubst_expr for sake of cp_finish_decl.  This fixes
consideration of explicit dguides/conversion when instantiating the
initializer of block-scope variables, but the static data member case is
still similarly broken since those are handled from instantiate_body
not tsubst_expr.

PR c++/102137
PR c++/87820

gcc/cp/ChangeLog:

* cp-tree.h (is_copy_initialization): Declare.
* init.cc (build_aggr_init): Split out copy-initialization
check into ...
(is_copy_initialization): ... here.
(tsubst_expr) : Pass LOOKUP_ONLYCONVERTING
to cp_finish_decl when is_copy_initialization is true.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/explicit15.C: New test.
* g++.dg/cpp1z/class-deduction108.C: New test.
---
 gcc/cp/cp-tree.h  |  1 +
 gcc/cp/init.cc| 20 +++--
 gcc/cp/pt.cc  | 

[PATCH] c++: non-constant non-dependent decltype folding [PR104823]

2022-03-07 Thread Patrick Palka via Gcc-patches
instantiate_non_dependent_expr_sfinae instantiates only potentially
constant expressions, but when processing a non-dependent decltype
operand we want to instantiate it even if it's non-constant since
such non-dependent decltype is always resolved ahead of time.

Currently finish_decltype_type uses the former function, which causes us
to miss issuing a narrowing diagnostic for S{id(v)} in the below testcase
because we never instantiate this non-constant non-dependent decltype
operand.

So this patch makes finish_decltype_type use i_n_d_e_internal instead of
_sfinae.  And afterward, we need to keep processing_template_decl cleared
for sake of the later call to lvalue_kind, which handles templated and
non-templated COND_EXPR differently.  Otherwise we'd incorrectly reject
the declaration of g in cpp0x/cond2.C with:

  error: ‘g’ declared as function returning a function

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

PR c++/104823

gcc/cp/ChangeLog:

* semantics.cc (finish_decltype_type): Use i_n_d_e_internal
instead of _sfinae when instantiating a non-dependent decltype
operand, and keep processing_template_decl cleared afterward.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/Wnarrowing19.C: New test.
---
 gcc/cp/semantics.cc   | 11 ++-
 gcc/testsuite/g++.dg/cpp0x/Wnarrowing19.C |  8 
 2 files changed, 18 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/Wnarrowing19.C

diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 07cae993efe..66d90c2f7be 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -11217,6 +11217,8 @@ finish_decltype_type (tree expr, bool 
id_expression_or_member_access_p,
   /* decltype is an unevaluated context.  */
   cp_unevaluated u;
 
+  processing_template_decl_sentinel ptds (/*reset=*/false);
+
   /* Depending on the resolution of DR 1172, we may later need to distinguish
  instantiation-dependent but not type-dependent expressions so that, say,
  A::U doesn't require 'typename'.  */
@@ -11232,7 +11234,14 @@ finish_decltype_type (tree expr, bool 
id_expression_or_member_access_p,
 }
   else if (processing_template_decl)
 {
-  expr = instantiate_non_dependent_expr_sfinae (expr, complain);
+  /* Instantiate the non-dependent operand to diagnose any ill-formed
+expressions.  And keep processing_template_decl cleared for the rest
+of the function (for sake of the call to lvalue_kind below, which
+handles templated and non-templated COND_EXPR differently).  */
+  processing_template_decl = 0;
+  /* Since we want to do this even for non-constant expressions, we
+use i_n_d_e_internal here instead of _sfinae.  */
+  expr = instantiate_non_dependent_expr_internal (expr, complain);
   if (expr == error_mark_node)
return error_mark_node;
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/Wnarrowing19.C 
b/gcc/testsuite/g++.dg/cpp0x/Wnarrowing19.C
new file mode 100644
index 000..bd9fd2eb6f9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/Wnarrowing19.C
@@ -0,0 +1,8 @@
+// PR c++/104823
+// { dg-do compile { target c++11 } }
+
+struct S { S(int); };
+
+double id(double v);
+
+template auto f(double v) -> decltype(S{id(v)}); // { dg-error 
"narrowing" }
-- 
2.35.1.354.g715d08a9e5



Re: [PATCH] c++: detecting copy-init context during CTAD [PR102137]

2022-03-07 Thread Patrick Palka via Gcc-patches
On Fri, 4 Mar 2022, Jason Merrill wrote:

> On 3/4/22 14:24, Patrick Palka wrote:
> > Here we're failing to communicate to cp_finish_decl from tsubst_expr
> > that we're in a copy-initialization context (via the LOOKUP_ONLYCONVERTING
> > flag), which causes do_class_deduction to always consider explicit
> > deduction guides when performing CTAD for a templated variable initializer.
> > 
> > We could fix this by passing LOOKUP_ONLYCONVERTING appropriately when
> > calling cp_finish_decl from tsubst_expr, but it seems do_class_deduction
> > can determine if we're in a copy-init context by simply inspecting the
> > initializer, and thus render its flags parameter unnecessary, which is
> > what this patch implements.  (If we were to fix this in tsubst_expr
> > instead, I think we'd have to inspect the initializer in the same way
> > in order to detect a copy-init context?)
> 
> Hmm, does this affect conversions as well?
> 
> Looks like it does:
> 
> struct A
> {
>   explicit operator int();
> };
> 
> template  void f()
> {
>   T t = A();
> }
> 
> int main()
> {
>   f(); // wrongly accepted
> }
> 
> The reverse, initializing via an explicit constructor, is caught by code in
> build_aggr_init much like the code your patch adds to do_auto_deduction;
> perhaps we should move/copy that code to cp_finish_decl?

Ah, makes sense.  Moving that code from build_aggr_init to
cp_finish_decl broke things, but using it in both spots seems to work
well.  And I suppose we might as well use it in do_class_deduction too,
since doing so lets us remove the flags parameter.

-- >8 --

Subject: [PATCH] c++: detecting copy-init context during CTAD [PR102137]

Here we're failing to communicate to cp_finish_decl from tsubst_expr
that we're in a copy-initialization context (via the LOOKUP_ONLYCONVERTING
flag), which causes us to always consider explicit deduction guides when
performing CTAD for a templated variable initializer.

It turns out this bug also affects consideration of explicit conversion
operators for the same reason.  But consideration of explicit constructors
is unaffected and seems to work correctly thanks to code in build_aggr_init
that sets LOOKUP_ONLYCONVERTING when the initializer represents
copy-initialization.

This patch factors out the copy-initialization test from build_aggr_init
and reuses it in tsubst_expr for sake of cp_finish_decl.  And we might
as well use it in do_class_deduction too, since doing so lets us get rid
of its flags parameter (which is used only to control whether explicit
deduction guides are considered).

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

PR c++/102137
PR c++/87820

gcc/cp/ChangeLog:

* cp-tree.h (is_copy_initialization): Declare.
(do_auto_deduction): Remove flags parameter.
* decl.cc (cp_finish_decl): Adjust call to do_auto_deduction.
* init.cc (build_aggr_init): Split out copy-initialization
check into ...
(is_copy_initialization): ... here.
* pt.cc (convert_template_argument): Adjust call to
do_auto_deduction.
(tsubst_expr) : Pass LOOKUP_ONLYCONVERTING
to cp_finish_decl when is_copy_initialization.
(do_class_deduction): Remove flags parameter, and instead
call is_copy_initialization to determine if we're in a copy-init
context.
(do_auto_deduction): Adjust call to do_class_deduction.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/explicit15.C: New test.
* g++.dg/cpp1z/class-deduction108.C: New test.
---
 gcc/cp/cp-tree.h  |  4 +--
 gcc/cp/decl.cc|  2 +-
 gcc/cp/init.cc| 20 +---
 gcc/cp/pt.cc  | 23 --
 gcc/testsuite/g++.dg/cpp0x/explicit15.C   | 31 +++
 .../g++.dg/cpp1z/class-deduction108.C | 31 +++
 6 files changed, 93 insertions(+), 18 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/explicit15.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction108.C

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index ac723901098..be556d2c441 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7039,6 +7039,7 @@ extern void emit_mem_initializers (tree);
 extern tree build_aggr_init(tree, tree, int,
  tsubst_flags_t);
 extern int is_class_type   (tree, int);
+extern bool is_copy_initialization (tree);
 extern tree build_zero_init(tree, tree, bool);
 extern tree build_value_init   (tree, tsubst_flags_t);
 extern tree build_value_init_noctor(tree, tsubst_flags_t);
@@ -7279,8 +7

[PATCH] c++: detecting copy-init context during CTAD [PR102137]

2022-03-04 Thread Patrick Palka via Gcc-patches
Here we're failing to communicate to cp_finish_decl from tsubst_expr
that we're in a copy-initialization context (via the LOOKUP_ONLYCONVERTING
flag), which causes do_class_deduction to always consider explicit
deduction guides when performing CTAD for a templated variable initializer.

We could fix this by passing LOOKUP_ONLYCONVERTING appropriately when
calling cp_finish_decl from tsubst_expr, but it seems do_class_deduction
can determine if we're in a copy-init context by simply inspecting the
initializer, and thus render its flags parameter unnecessary, which is
what this patch implements.  (If we were to fix this in tsubst_expr
instead, I think we'd have to inspect the initializer in the same way
in order to detect a copy-init context?)

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

PR c++/102137

gcc/cp/ChangeLog:

* cp-tree.h (do_auto_deduction): Remove flags parameter.
* decl.cc (cp_finish_decl): Adjust call to do_auto_deduction.
* pt.cc (convert_template_argument): Likewise.
(do_class_deduction): Remove flags parameter and instead
determine if we're in a copy-init context by inspecting the
initializer.
(do_auto_deduction): Adjust call to do_class_deduction.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/class-deduction108.C: New test.
---
 gcc/cp/cp-tree.h  |  3 +-
 gcc/cp/decl.cc|  2 +-
 gcc/cp/pt.cc  | 23 +++--
 .../g++.dg/cpp1z/class-deduction108.C | 32 +++
 4 files changed, 48 insertions(+), 12 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction108.C

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index ac723901098..c2ef6544389 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7279,8 +7279,7 @@ extern tree do_auto_deduction   (tree, 
tree, tree,
 = tf_warning_or_error,
  auto_deduction_context
 = adc_unspecified,
-tree = NULL_TREE,
-int = LOOKUP_NORMAL);
+tree = NULL_TREE);
 extern tree type_uses_auto (tree);
 extern tree type_uses_auto_or_concept  (tree);
 extern void append_type_to_template_for_access_check (tree, tree, tree,
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 199ac768d43..152f657e9f2 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -8039,7 +8039,7 @@ cp_finish_decl (tree decl, tree init, bool 
init_const_expr_p,
outer_targs = DECL_TI_ARGS (decl);
   type = TREE_TYPE (decl) = do_auto_deduction (type, d_init, auto_node,
   tf_warning_or_error, adc,
-  outer_targs, flags);
+  outer_targs);
   if (type == error_mark_node)
return;
   if (TREE_CODE (type) == FUNCTION_TYPE)
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index d94d4538faa..66fc8cacdc6 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -8567,8 +8567,7 @@ convert_template_argument (tree parm,
   can happen in the context of -fnew-ttp-matching.  */;
   else if (tree a = type_uses_auto (t))
{
- t = do_auto_deduction (t, arg, a, complain, adc_unify, args,
-LOOKUP_IMPLICIT);
+ t = do_auto_deduction (t, arg, a, complain, adc_unify, args);
  if (t == error_mark_node)
return error_mark_node;
}
@@ -29832,8 +29831,7 @@ ctad_template_p (tree tmpl)
type.  */
 
 static tree
-do_class_deduction (tree ptype, tree tmpl, tree init,
-   int flags, tsubst_flags_t complain)
+do_class_deduction (tree ptype, tree tmpl, tree init, tsubst_flags_t complain)
 {
   /* We should have handled this in the caller.  */
   if (DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl))
@@ -29881,6 +29879,13 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
   if (type_dependent_expression_p (init))
 return ptype;
 
+  bool copy_init_p = true;
+  if (!init
+  || TREE_CODE (init) == TREE_LIST
+  || (BRACE_ENCLOSED_INITIALIZER_P (init)
+ && CONSTRUCTOR_IS_DIRECT_INIT (init)))
+copy_init_p = false;
+
   tree type = TREE_TYPE (tmpl);
 
   bool try_list_ctor = false;
@@ -29929,7 +29934,7 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
   /* Prune explicit deduction guides in copy-initialization context (but
  not copy-list-initialization).  */
   bool elided = false;
-  if (!list_init_p && (flags & LOOKUP_ONLYCONVERTING))
+  if (!list_init_p && copy_init_p)
 {
   for (lkp_iterator iter (cands); !elided && iter; ++iter)
if (DECL_NONCONVERTING_P (STRIP_TEMPLATE 

[committed] c++: Add testcase for already fixed PR [PR103443]

2022-03-04 Thread Patrick Palka via Gcc-patches
Fixed by r12-7264.

PR c++/103443

gcc/testsuite/ChangeLog:

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

diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval29.C 
b/gcc/testsuite/g++.dg/cpp2a/consteval29.C
new file mode 100644
index 000..61590225bd6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/consteval29.C
@@ -0,0 +1,20 @@
+// PR c++/103443
+// { dg-do compile { target c++20 } }
+
+template
+struct A { };
+
+template
+consteval unsigned index_sequence2mask(A) {
+  if constexpr (sizeof...(Is) == 0u)
+return 0u;
+  else
+return ((1u << Is) | ...);
+}
+
+template{})>
+void use_mask();
+
+int main() {
+  use_mask();
+}
-- 
2.35.1.354.g715d08a9e5



[PATCH] c++: merge default targs for function templates [PR65396]

2022-03-03 Thread Patrick Palka via Gcc-patches
We currently merge default template arguments for class templates, but
not for function templates.  This patch fixes this by splitting out the
argument merging logic in redeclare_class_template into a separate
function and using it in duplicate_decls as well.

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

PR c++/65396

gcc/cp/ChangeLog:

* cp-tree.h (merge_default_template_args): Declare.
* decl.cc (merge_default_template_args): Define, split out from
redeclare_class_template.
(duplicate_decls): Use it when merging member function template
and free function declarations.
* pt.cc (redeclare_class_template): Split out default argument
merging logic into merge_default_template_args.  Improve location
of a note when there's a template parameter kind mismatch.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/vt-34314.C: Adjust expected location of
"redeclared here" note.
* g++.dg/template/pr92440.C: Likewise.
* g++.old-deja/g++.pt/redecl1.C: Adjust expected location of
"redefinition of default argument" error.
* g++.dg/template/defarg23.C: New test.
* g++.dg/template/defarg23a.C: New test.
---
 gcc/cp/cp-tree.h|  1 +
 gcc/cp/decl.cc  | 60 -
 gcc/cp/pt.cc| 31 ++-
 gcc/testsuite/g++.dg/cpp0x/vt-34314.C   | 12 ++---
 gcc/testsuite/g++.dg/template/defarg23.C| 21 
 gcc/testsuite/g++.dg/template/defarg23a.C   | 24 +
 gcc/testsuite/g++.dg/template/pr92440.C |  4 +-
 gcc/testsuite/g++.old-deja/g++.pt/redecl1.C | 12 ++---
 8 files changed, 123 insertions(+), 42 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/defarg23.C
 create mode 100644 gcc/testsuite/g++.dg/template/defarg23a.C

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 8a44218611f..ea53e2d0ef2 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6783,6 +6783,7 @@ extern void note_iteration_stmt_body_end  (bool);
 extern void determine_local_discriminator  (tree);
 extern int decls_match (tree, tree, bool = true);
 extern bool maybe_version_functions(tree, tree, bool);
+extern bool merge_default_template_args(tree, tree, bool);
 extern tree duplicate_decls(tree, tree,
 bool hiding = false,
 bool was_hidden = false);
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 23c06655bde..a0bce56c121 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -1470,6 +1470,43 @@ duplicate_function_template_decls (tree newdecl, tree 
olddecl)
   return false;
 }
 
+/* OLD_PARMS is the innermost set of template parameters for some template
+   declaration, and NEW_PARMS is the corresponding set of template parameters
+   for a redeclaration of that template.  Merge the default arguments within
+   these two sets of parameters.  CLASS_P is true iff the template in
+   question is a class template.  */
+
+bool
+merge_default_template_args (tree new_parms, tree old_parms, bool class_p)
+{
+  gcc_checking_assert (TREE_VEC_LENGTH (new_parms)
+  == TREE_VEC_LENGTH (old_parms));
+  for (int i = 0; i < TREE_VEC_LENGTH (new_parms); i++)
+{
+  tree new_parm = TREE_VALUE (TREE_VEC_ELT (new_parms, i));
+  tree old_parm = TREE_VALUE (TREE_VEC_ELT (old_parms, i));
+  tree& new_default = TREE_PURPOSE (TREE_VEC_ELT (new_parms, i));
+  tree& old_default = TREE_PURPOSE (TREE_VEC_ELT (old_parms, i));
+  if (new_default != NULL_TREE && old_default != NULL_TREE)
+   {
+ auto_diagnostic_group d;
+ error ("redefinition of default argument for %q+#D", new_parm);
+ inform (DECL_SOURCE_LOCATION (old_parm),
+ "original definition appeared here");
+ return false;
+   }
+  else if (new_default != NULL_TREE)
+   /* Update the previous template parameters (which are the ones
+  that will really count) with the new default value.  */
+   old_default = new_default;
+  else if (class_p && old_default != NULL_TREE)
+   /* Update the new parameters, too; they'll be used as the
+  parameters for any members.  */
+   new_default = old_default;
+}
+  return true;
+}
+
 /* If NEWDECL is a redeclaration of OLDDECL, merge the declarations.
If the redeclaration is invalid, a diagnostic is issued, and the
error_mark_node is returned.  Otherwise, OLDDECL is returned.
@@ -1990,7 +2027,23 @@ duplicate_decls (tree newdecl, tree olddecl, bool 
hiding, bool was_hidden)
 template shall be specified on the initial declaration
 of the member function within the class template.  */
  || CLASSTYPE_TEMPLATE_INFO (CP_DECL_CONTEXT (olddecl
- 

[PATCH] c++: naming a dependently-scoped template for CTAD [PR104641]

2022-03-02 Thread Patrick Palka via Gcc-patches
In order to be able to perform CTAD for a dependently-scoped template
such as A::B in the testcase below, we need to permit a
typename-specifier to resolve to a template as per [dcl.type.simple]/2,
at least when it appears in a CTAD-enabled context.

This patch implements this using a new tsubst flag tf_tst_ok to control
when a TYPENAME_TYPE is allowed to name a template, and sets this flag
when substituting into the type of a CAST_EXPR, CONSTRUCTOR or VAR_DECL
(each of which is a CTAD-enabled context).

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

PR c++/104641

gcc/cp/ChangeLog:

* cp-tree.h (tsubst_flags::tf_tst_ok): New flag.
* decl.cc (make_typename_type): Allow a typename-specifier to
resolve to a template when tf_tst_ok.
* pt.cc (tsubst_decl) : Set tf_tst_ok when
substituting the type.
(tsubst): Clear tf_tst_ok and remember if it was set.
: Pass tf_tst_ok to make_typename_type
appropriately.  Do make_template_placeholder when when
make_typename_type returns a TEMPLATE_DECL.
(tsubst_copy) : Set tf_tst_ok when substituting
the type.
(tsubst_copy_and_build) : Likewise.
: Likewise.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/class-deduction107.C: New test.
---
 gcc/cp/cp-tree.h  |  2 ++
 gcc/cp/decl.cc| 14 +---
 gcc/cp/pt.cc  | 35 +++
 .../g++.dg/cpp1z/class-deduction107.C | 20 +++
 4 files changed, 61 insertions(+), 10 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction107.C

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index da63d51d9bc..8a44218611f 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5551,6 +5551,8 @@ enum tsubst_flags {
(build_target_expr and friends) */
   tf_norm = 1 << 11,/* Build diagnostic information during
constraint normalization.  */
+  tf_tst_ok = 1 << 12,  /* Allow a typename-specifier to name
+   a template.  */
   /* Convenient substitution flags combinations.  */
   tf_warning_or_error = tf_warning | tf_error
 };
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 7f80f9d4d7a..23c06655bde 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -4148,10 +4148,16 @@ make_typename_type (tree context, tree name, enum 
tag_types tag_type,
 }
   if (!want_template && TREE_CODE (t) != TYPE_DECL)
 {
-  if (complain & tf_error)
-   error ("% names %q#T, which is not a type",
-  context, name, t);
-  return error_mark_node;
+  if ((complain & tf_tst_ok) && DECL_TYPE_TEMPLATE_P (t))
+   /* The caller permits this typename-specifier to name a template
+  (because it appears in a CTAD-enabled context).  */;
+  else
+   {
+ if (complain & tf_error)
+   error ("% names %q#T, which is not a type",
+  context, name, t);
+ return error_mark_node;
+   }
 }
 
   if (!check_accessibility_of_qualified_id (t, /*object_type=*/NULL_TREE,
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 8fb17349ee1..18a21572ce3 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -14926,7 +14926,10 @@ tsubst_decl (tree t, tree args, tsubst_flags_t 
complain)
&& VAR_HAD_UNKNOWN_BOUND (t)
&& type != error_mark_node)
  type = strip_array_domain (type);
-   type = tsubst (type, args, complain, in_decl);
+   tsubst_flags_t tcomplain = complain;
+   if (VAR_P (t))
+ tcomplain |= tf_tst_ok;
+   type = tsubst (type, args, tcomplain, in_decl);
/* Substituting the type might have recursively instantiated this
   same alias (c++/86171).  */
if (gen_tmpl && DECL_ALIAS_TEMPLATE_P (gen_tmpl)
@@ -15612,6 +15615,9 @@ tsubst (tree t, tree args, tsubst_flags_t complain, 
tree in_decl)
   bool fndecl_type = (complain & tf_fndecl_type);
   complain &= ~tf_fndecl_type;
 
+  bool tst_ok = (complain & tf_tst_ok);
+  complain &= ~tf_tst_ok;
+
   if (type
   && code != TYPENAME_TYPE
   && code != TEMPLATE_TYPE_PARM
@@ -16199,8 +16205,10 @@ tsubst (tree t, tree args, tsubst_flags_t complain, 
tree in_decl)
  return error_mark_node;
  }
 
-   f = make_typename_type (ctx, f, typename_type,
-   complain | tf_keep_type_decl);
+   tsubst_flags_t tcomplain = complain | tf_keep_type_decl;
+   if (tst_ok)
+ tcomplain |= tf_tst_ok;
+   f = make_typename_type (ctx, f, typename_type, tcomplain);
if (f == error_mark_node)
  return f;
if (TREE_CODE (f) == TYPE_DECL)
@@ -16229,6 +16237,12 @@ tsubst (tree t, tree args, tsubst_flags_t complain, 
tree in_decl)
  }
  }
 
+   if 

[PATCH] c++: fold calls to std::move/forward [PR96780]

2022-03-01 Thread Patrick Palka via Gcc-patches
A well-formed call to std::move/forward is equivalent to a cast, but the
former being a function call means it comes with bloated debug info, which
persists even after the call has been inlined away, for an operation that
is never interesting to debug.

This patch addresses this problem in a relatively ad-hoc way by folding
calls to std::move/forward into casts as part of the frontend's general
expression folding routine.  After this patch with -O2 and a non-checking
compiler, debug info size for some testcases decreases by about ~10% and
overall compile time and memory usage decreases by ~2%.

Bootstrapped and regtested on x86_64-pc-linux-gnu, is this something we
want to consider for GCC 12?

PR c++/96780

gcc/cp/ChangeLog:

* cp-gimplify.cc (cp_fold) : When optimizing,
fold calls to std::move/forward into simple casts.
* cp-tree.h (is_std_move_p, is_std_forward_p): Declare.
* typeck.cc (is_std_move_p, is_std_forward_p): Export.

gcc/testsuite/ChangeLog:

* g++.dg/opt/pr96780.C: New test.
---
 gcc/cp/cp-gimplify.cc  | 18 ++
 gcc/cp/cp-tree.h   |  2 ++
 gcc/cp/typeck.cc   |  6 ++
 gcc/testsuite/g++.dg/opt/pr96780.C | 24 
 4 files changed, 46 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/opt/pr96780.C

diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
index d7323fb5c09..0b009b631c7 100644
--- a/gcc/cp/cp-gimplify.cc
+++ b/gcc/cp/cp-gimplify.cc
@@ -2756,6 +2756,24 @@ cp_fold (tree x)
 
 case CALL_EXPR:
   {
+   if (optimize
+   && (is_std_move_p (x) || is_std_forward_p (x)))
+ {
+   /* When optimizing, "inline" calls to std::move/forward by
+  simply folding them into the corresponding cast.  This is
+  cheaper than relying on the inliner to do so, and also
+  means we avoid generating useless debug info for them at all.
+
+  At this point the argument has already been coerced into a
+  reference, so it suffices to use a NOP_EXPR to express the
+  reference-to-reference cast.  */
+   r = CALL_EXPR_ARG (x, 0);
+   if (!same_type_p (TREE_TYPE (x), TREE_TYPE (r)))
+ r = build_nop (TREE_TYPE (x), r);
+   x = cp_fold (r);
+   break;
+ }
+
int sv = optimize, nw = sv;
tree callee = get_callee_fndecl (x);
 
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 37d462fca6e..ab828730b03 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -8089,6 +8089,8 @@ extern tree finish_right_unary_fold_expr (tree, int);
 extern tree finish_binary_fold_expr  (tree, tree, int);
 extern tree treat_lvalue_as_rvalue_p(tree, bool);
 extern bool decl_in_std_namespace_p (tree);
+extern bool is_std_move_p   (tree);
+extern bool is_std_forward_p(tree);
 
 /* in typeck2.cc */
 extern void require_complete_eh_spec_types (tree, tree);
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index bddc83759ad..a3644f8e7f7 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -62,8 +62,6 @@ static bool maybe_warn_about_returning_address_of_local 
(tree, location_t = UNKN
 static void error_args_num (location_t, tree, bool);
 static int convert_arguments (tree, vec **, tree, int,
   tsubst_flags_t);
-static bool is_std_move_p (tree);
-static bool is_std_forward_p (tree);
 
 /* Do `exp = require_complete_type (exp);' to make sure exp
does not have an incomplete type.  (That includes void types.)
@@ -10207,7 +10205,7 @@ decl_in_std_namespace_p (tree decl)
 
 /* Returns true if FN, a CALL_EXPR, is a call to std::forward.  */
 
-static bool
+bool
 is_std_forward_p (tree fn)
 {
   /* std::forward only takes one argument.  */
@@ -10224,7 +10222,7 @@ is_std_forward_p (tree fn)
 
 /* Returns true if FN, a CALL_EXPR, is a call to std::move.  */
 
-static bool
+bool
 is_std_move_p (tree fn)
 {
   /* std::move only takes one argument.  */
diff --git a/gcc/testsuite/g++.dg/opt/pr96780.C 
b/gcc/testsuite/g++.dg/opt/pr96780.C
new file mode 100644
index 000..ca24b2802bb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/pr96780.C
@@ -0,0 +1,24 @@
+// PR c++/96780
+// Verify calls to std::move/forward are folded away by the frontend.
+// { dg-do compile { target c++11 } }
+// { dg-additional-options "-O -fdump-tree-gimple" }
+
+#include 
+
+struct A;
+
+extern A& a;
+extern const A& ca;
+
+void f() {
+  auto&& x1 = std::move(a);
+  auto&& x2 = std::forward(a);
+  auto&& x3 = std::forward(a);
+
+  auto&& x4 = std::move(ca);
+  auto&& x5 = std::forward(ca);
+  auto&& x6 = std::forward(ca);
+}
+
+// { dg-final { scan-tree-dump-not "= std::move" "gimple" } }
+// { dg-final { scan-tree-dump-not "= std::forward" "gimple" } }
-- 
2.35.1.354.g715d08a9e5



Re: [PATCH] c++: return-type-req in constraint using only outer tparms [PR104527]

2022-03-01 Thread Patrick Palka via Gcc-patches
On Wed, Feb 16, 2022 at 2:56 PM Patrick Palka  wrote:
>
> On Tue, 15 Feb 2022, Jason Merrill wrote:
>
> > On 2/14/22 11:32, Patrick Palka wrote:
> > > Here the template context for the atomic constraint has two levels of
> > > template arguments, but since it depends only on the innermost argument
> > > T we use a single-level argument vector during substitution into the
> > > constraint (built by get_mapped_args).  We eventually pass this vector
> > > to do_auto_deduction as part of checking the return-type-requirement
> > > inside the atom, but do_auto_deduction expects outer_targs to be a full
> > > set of arguments for sake of satisfaction.
> >
> > Could we note the current number of levels in the map and use that in
> > get_mapped_args instead of the highest level parameter we happened to use?
>
> Ah yeah, that seems to work nicely.  IIUC it should suffice to remember
> whether the atomic constraint expression came from a concept definition.
> If it did, then the depth of the argument vector returned by
> get_mapped_args must be one, otherwise (as in the testcase) it must be
> the same as the template depth of the constrained entity, which is the
> depth of ARGS.
>
> How does the following look?  Bootstrapped and regtested on
> x86_64-pc-linux-gnu and also on cmcstl2 and range-v3.

Ping.

>
> -- >8 --
>
> Subject: [PATCH] c++: return-type-req in constraint using only outer tparms
>  [PR104527]
>
> Here the template context for the atomic constraint has two levels of
> template parameters, but since it depends only on the innermost parameter
> T we use a single-level argument vector (built by get_mapped_args) during
> substitution into the atom.  We eventually pass this vector to
> do_auto_deduction as part of checking the return-type-requirement within
> the atom, but do_auto_deduction expects outer_targs to be a full set of
> arguments for sake of satisfaction.
>
> This patch fixes this by making get_mapped_args always return an
> argument vector whose depth corresponds to the template depth of the
> context in which the atomic constraint expression was written, instead
> of the highest parameter level that the expression happens to use.
>
> PR c++/104527
>
> gcc/cp/ChangeLog:
>
> * constraint.cc (normalize_atom): Set
> ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P appropriately.
> (get_mapped_args):  Make static, adjust parameters.  Always
> return a vector whose depth corresponds to the template depth of
> the context of the atomic constraint expression.  Micro-optimize
> by passing false as exact to safe_grow_cleared and by collapsing
> a multi-level depth-one argument vector.
> (satisfy_atom): Adjust call to get_mapped_args and
> diagnose_atomic_constraint.
> (diagnose_atomic_constraint): Replace map parameter with an args
> parameter.
> * cp-tree.h (ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P): Define.
> (get_mapped_args): Remove declaration.
>
> gcc/testsuite/ChangeLog:
>
> * g++.dg/cpp2a/concepts-return-req4.C: New test.
> ---
>  gcc/cp/constraint.cc  | 64 +++
>  gcc/cp/cp-tree.h  |  7 +-
>  .../g++.dg/cpp2a/concepts-return-req4.C   | 24 +++
>  3 files changed, 69 insertions(+), 26 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C
>
> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> index 12db7e5cf14..306e28955c6 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -764,6 +764,8 @@ normalize_atom (tree t, tree args, norm_info info)
>tree ci = build_tree_list (t, info.context);
>
>tree atom = build1 (ATOMIC_CONSTR, ci, map);
> +  if (info.in_decl && concept_definition_p (info.in_decl))
> +ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (atom) = true;
>if (!info.generate_diagnostics ())
>  {
>/* Cache the ATOMIC_CONSTRs that we return, so that sat_hasher::equal
> @@ -2826,33 +2828,37 @@ satisfaction_value (tree t)
>  return boolean_true_node;
>  }
>
> -/* Build a new template argument list with template arguments corresponding
> -   to the parameters used in an atomic constraint.  */
> +/* Build a new template argument vector according to the parameter
> +   mapping of the atomic constraint T, using arguments from ARGS.  */
>
> -tree
> -get_mapped_args (tree map)
> +static tree
> +get_mapped_args (tree t, tree args)
>  {
> +  tree map = ATOMIC_CONSTR_MAP (t);
> +
>/* No map, no arguments.  */
>if (!map)
>  return NULL_TREE;
>
> 

Re: [PATCH] c++: memory corruption during name lookup w/ modules [PR99479]

2022-03-01 Thread Patrick Palka via Gcc-patches
On Thu, Feb 17, 2022 at 3:24 PM Patrick Palka  wrote:
>
> name_lookup::search_unqualified uses a statically allocated vector
> in order to avoid repeated reallocation, under the assumption that
> the function can't be called recursively.  With modules however,
> this assumption turns out to be false, and search_unqualified can
> be called recursively as demonstrated by testcase in comment #19
> of PR99479[1] where the recursive call causes the vector to get
> reallocated which invalidates the reference held by the parent call.
>
> This patch makes search_unqualified instead use an auto_vec with 16
> elements of internal storage (since with the various libraries I tested,
> the size of the vector never exceeded 12).  In turn we can simplify the
> API of subroutines to take the vector by reference and return void.
>
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk?

Ping.

>
> [1]: https://gcc.gnu.org/PR99479#c19
>
> PR c++/99479
>
> gcc/cp/ChangeLog:
>
> * name-lookup.cc (name_lookup::using_queue): Change to an
> auto_vec (with 16 elements of internal storage).
> (name_lookup::queue_namespace): Change return type to void,
> take queue parameter by reference and adjust function body
> accordingly.
> (name_lookup::do_queue_usings): Inline into ...
> (name_lookup::queue_usings): ... here.  As in queue_namespace.
> (name_lookup::search_unqualified): Don't make queue static,
> assume its incoming length is 0, and adjust function body
> accordingly.
> ---
>  gcc/cp/name-lookup.cc | 62 +++
>  1 file changed, 22 insertions(+), 40 deletions(-)
>
> diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
> index 93c4eb7193b..5c965d6fba1 100644
> --- a/gcc/cp/name-lookup.cc
> +++ b/gcc/cp/name-lookup.cc
> @@ -429,7 +429,7 @@ class name_lookup
>  {
>  public:
>typedef std::pair using_pair;
> -  typedef vec using_queue;
> +  typedef auto_vec using_queue;
>
>  public:
>tree name;   /* The identifier being looked for.  */
> @@ -528,16 +528,8 @@ private:
>bool search_usings (tree scope);
>
>  private:
> -  using_queue *queue_namespace (using_queue *queue, int depth, tree scope);
> -  using_queue *do_queue_usings (using_queue *queue, int depth,
> -   vec *usings);
> -  using_queue *queue_usings (using_queue *queue, int depth,
> -vec *usings)
> -  {
> -if (usings)
> -  queue = do_queue_usings (queue, depth, usings);
> -return queue;
> -  }
> +  void queue_namespace (using_queue& queue, int depth, tree scope);
> +  void queue_usings (using_queue& queue, int depth, vec 
> *usings);
>
>  private:
>void add_fns (tree);
> @@ -1084,39 +1076,35 @@ name_lookup::search_qualified (tree scope, bool 
> usings)
>  /* Add SCOPE to the unqualified search queue, recursively add its
> inlines and those via using directives.  */
>
> -name_lookup::using_queue *
> -name_lookup::queue_namespace (using_queue *queue, int depth, tree scope)
> +void
> +name_lookup::queue_namespace (using_queue& queue, int depth, tree scope)
>  {
>if (see_and_mark (scope))
> -return queue;
> +return;
>
>/* Record it.  */
>tree common = scope;
>while (SCOPE_DEPTH (common) > depth)
>  common = CP_DECL_CONTEXT (common);
> -  vec_safe_push (queue, using_pair (common, scope));
> +  queue.safe_push (using_pair (common, scope));
>
>/* Queue its inline children.  */
>if (vec *inlinees = DECL_NAMESPACE_INLINEES (scope))
>  for (unsigned ix = inlinees->length (); ix--;)
> -  queue = queue_namespace (queue, depth, (*inlinees)[ix]);
> +  queue_namespace (queue, depth, (*inlinees)[ix]);
>
>/* Queue its using targets.  */
> -  queue = queue_usings (queue, depth, NAMESPACE_LEVEL 
> (scope)->using_directives);
> -
> -  return queue;
> +  queue_usings (queue, depth, NAMESPACE_LEVEL (scope)->using_directives);
>  }
>
>  /* Add the namespaces in USINGS to the unqualified search queue.  */
>
> -name_lookup::using_queue *
> -name_lookup::do_queue_usings (using_queue *queue, int depth,
> - vec *usings)
> +void
> +name_lookup::queue_usings (using_queue& queue, int depth, vec 
> *usings)
>  {
> -  for (unsigned ix = usings->length (); ix--;)
> -queue = queue_namespace (queue, depth, (*usings)[ix]);
> -
> -  return queue;
> +  if (usings)
> +for (unsigned ix = usings->length (); ix--;)
> +  queue_namespace (queue, depth, (*usings)[ix]);
>  }
>
>  /*

[PATCH] c++: improve location of fold expressions

2022-02-28 Thread Patrick Palka via Gcc-patches
This improves diagnostic quality for unsatisfied atomic constraints
that consist of a fold expression, e.g. in concepts/diagnostics3.C:

  .../diagnostic3.C:10:22: note: the expression ‘(foo && ...) [with Ts = 
{int, char}]’ evaluated to ‘false’
 10 | requires (foo && ...)
|  ^~~~

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

gcc/cp/ChangeLog:

* semantics.cc (finish_unary_fold_expr): Use input_location
instead of UNKNOWN_LOCATION.
(finish_binary_fold_expr): Likewise.

gcc/testsuite/ChangeLog:

* g++.dg/concepts/diagnostic3.C: Adjusted expected location of
"evaluated to false" diagnostics.
---
 gcc/cp/semantics.cc | 4 ++--
 gcc/testsuite/g++.dg/concepts/diagnostic3.C | 8 
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index a2c0eb050e6..07cae993efe 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12185,7 +12185,7 @@ finish_unary_fold_expr (tree expr, int op, tree_code 
dir)
 
   /* Build the fold expression.  */
   tree code = build_int_cstu (integer_type_node, abs (op));
-  tree fold = build_min_nt_loc (UNKNOWN_LOCATION, dir, code, pack);
+  tree fold = build_min_nt_loc (input_location, dir, code, pack);
   FOLD_EXPR_MODIFY_P (fold) = (op < 0);
   TREE_TYPE (fold) = build_dependent_operator_type (NULL_TREE,
FOLD_EXPR_OP (fold),
@@ -12214,7 +12214,7 @@ finish_binary_fold_expr (tree pack, tree init, int op, 
tree_code dir)
 {
   pack = make_pack_expansion (pack);
   tree code = build_int_cstu (integer_type_node, abs (op));
-  tree fold = build_min_nt_loc (UNKNOWN_LOCATION, dir, code, pack, init);
+  tree fold = build_min_nt_loc (input_location, dir, code, pack, init);
   FOLD_EXPR_MODIFY_P (fold) = (op < 0);
   TREE_TYPE (fold) = build_dependent_operator_type (NULL_TREE,
FOLD_EXPR_OP (fold),
diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic3.C 
b/gcc/testsuite/g++.dg/concepts/diagnostic3.C
index 7796e264251..410651a9c1a 100644
--- a/gcc/testsuite/g++.dg/concepts/diagnostic3.C
+++ b/gcc/testsuite/g++.dg/concepts/diagnostic3.C
@@ -7,18 +7,18 @@ template
   concept foo = (bool)(foo_v | foo_v);
 
 template
-requires (foo && ...)
+requires (foo && ...) // { dg-message "with Ts = .int, char... evaluated 
to .false." }
 void
-bar() // { dg-message "with Ts = .int, char... evaluated to .false." }
+bar()
 { }
 
 template
 struct S { };
 
 template
-requires (foo> && ...)
+requires (foo> && ...) // { dg-message "with Is = .2, 3, 4... evaluated 
to .false." }
 void
-baz() // { dg-message "with Is = .2, 3, 4... evaluated to .false." }
+baz()
 { }
 
 void
-- 
2.35.1.354.g715d08a9e5



Re: [PATCH] c++: Fix ICE with non-constant satisfaction [PR98644]

2022-02-28 Thread Patrick Palka via Gcc-patches
On Tue, 19 Jan 2021, Jason Merrill wrote:

> On 1/13/21 12:05 PM, Patrick Palka wrote:
> > In the below testcase, the expression of the atomic constraint after
> > substitution is (int *) NON_LVALUE_EXPR <1> != 0B which is not a C++
> > constant expression, but its TREE_CONSTANT flag is set (from build2),
> > so satisfy_atom fails to notice that it's non-constant (and we end
> > up tripping over the assert in satisfaction_value).
> > 
> > Since TREE_CONSTANT doesn't necessarily correspond to C++ constantness,
> > this patch makes satisfy_atom instead check is_rvalue_constant_expression.
> > 
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > trunk/10?
> > 
> > gcc/cp/ChangeLog:
> > 
> > PR c++/98644
> > * constraint.cc (satisfy_atom): Check is_rvalue_constant_expression
> > instead of TREE_CONSTANT.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > PR c++/98644
> > * g++.dg/cpp2a/concepts-pr98644.C: New test.
> > ---
> >   gcc/cp/constraint.cc  | 2 +-
> >   gcc/testsuite/g++.dg/cpp2a/concepts-pr98644.C | 7 +++
> >   2 files changed, 8 insertions(+), 1 deletion(-)
> >   create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-pr98644.C
> > 
> > diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> > index 9049d087859..f99a25dc8a4 100644
> > --- a/gcc/cp/constraint.cc
> > +++ b/gcc/cp/constraint.cc
> > @@ -2969,7 +2969,7 @@ satisfy_atom (tree t, tree args, sat_info info)
> >   {
> > result = maybe_constant_value (result, NULL_TREE,
> >  /*manifestly_const_eval=*/true);
> > -  if (!TREE_CONSTANT (result))
> 
> This should be sufficient.  If the result isn't constant, maybe_constant_value
> shouldn't return it with TREE_CONSTANT set.  See
> 
> >   /* This isn't actually constant, so unset TREE_CONSTANT.  
> >
> 
> in cxx_eval_outermost_constant_expr.

I see, so the problem seems to be that the fail-fast path of
maybe_constant_value isn't clearing TREE_CONSTANT sufficiently.  Would
it make sense to fix this like so?

-- >8 --

Subject: [PATCH] c++: ICE with non-constant satisfaction value [PR98644]

Here during satisfaction the expression of the atomic constraint after
substitution is (int *) NON_LVALUE_EXPR <1> != 0B, which is not a C++
constant expression due to the reinterpret_cast, but TREE_CONSTANT is
set since its value is otherwise effectively constant.  We then call
maybe_constant_value on it, which proceeds via its fail-fast path to
exit early without clearing TREE_CONSTANT.  But satisfy_atom relies
on checking TREE_CONSTANT of the result of maybe_constant_value in order
to detect non-constant satisfaction.

This patch fixes this by making the fail-fast path of maybe_constant_value
clear TREE_CONSTANT in this case, like cxx_eval_outermost_constant_expr
in the normal path would have done.

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

PR c++/98644

gcc/cp/ChangeLog:

* constexpr.cc (maybe_constant_value): In the fail-fast path,
clear TREE_CONSTANT on the result if it's set on the input.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts-pr98644.C: New test.
* g++.dg/parse/array-size2.C: Remove expected diagnostic about a
narrowing conversion.
---
 gcc/cp/constexpr.cc   | 4 +++-
 gcc/testsuite/g++.dg/cpp2a/concepts-pr98644.C | 7 +++
 gcc/testsuite/g++.dg/parse/array-size2.C  | 2 --
 3 files changed, 10 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-pr98644.C

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 4716694cb71..234cf0acc26 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -7965,8 +7965,10 @@ maybe_constant_value (tree t, tree decl, bool 
manifestly_const_eval)
 
   if (!is_nondependent_constant_expression (t))
 {
-  if (TREE_OVERFLOW_P (t))
+  if (TREE_OVERFLOW_P (t)
+ || (!processing_template_decl && TREE_CONSTANT (t)))
{
+ /* This isn't actually constant, so unset TREE_CONSTANT.  */
  t = build_nop (TREE_TYPE (t), t);
  TREE_CONSTANT (t) = false;
}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr98644.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-pr98644.C
new file mode 100644
index 000..6772f72a3ce
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr98644.C
@@ -0,0 +1,7 @@
+// PR c++/98644
+// { dg-do compile { target c++20 } }
+
+template concept Signed = bool(T(1)); // { dg-error 
"reinterpret_cast" }
+static_assert(Signed); // { dg-error "non-constant" }
+
+constexpr bool B =

[PATCH] libstdc++: Implement P2415R2 "What is a view?"

2022-02-21 Thread Patrick Palka via Gcc-patches
Tested on x86_64-pc-linux-gnu, does this look OK for trunk?

libstdc++-v3/ChangeLog:

* include/bits/ranges_base.h (__detail::__is_initializer_list):
Define.
(viewable_range): Adjust as per P2415R2.
* include/std/ranges (owning_view): Define as per P2415R2.
(enable_borrowed_range): Likewise.
(views::__detail::__can_subrange): Replace with ...
(views::__detail::__can_owning_view): ... this.
(views::_All::_S_noexcept): Sync with operator().
(views::_All::operator()): Use owning_view instead of subrange
as per P2415R2.
* testsuite/std/ranges/adaptors/all.cc (test06): Adjust now that
views::all uses owning_view instead of subrange.
(test08): New test.
* testsuite/std/ranges/adaptors/lazy_split.cc (test09): Adjust
now that rvalue non-view non-borrowed ranges are viewable.
* testsuite/std/ranges/adaptors/split.cc (test06): Likewise.
---
 libstdc++-v3/include/bits/ranges_base.h   | 16 +++-
 libstdc++-v3/include/std/ranges   | 89 ++-
 .../testsuite/std/ranges/adaptors/all.cc  | 59 
 .../std/ranges/adaptors/lazy_split.cc | 13 ++-
 .../testsuite/std/ranges/adaptors/split.cc| 13 ++-
 5 files changed, 157 insertions(+), 33 deletions(-)

diff --git a/libstdc++-v3/include/bits/ranges_base.h 
b/libstdc++-v3/include/bits/ranges_base.h
index 3c5f4b1790a..38db33fd2ce 100644
--- a/libstdc++-v3/include/bits/ranges_base.h
+++ b/libstdc++-v3/include/bits/ranges_base.h
@@ -634,7 +634,7 @@ namespace ranges
 template
   concept __is_derived_from_view_interface
= requires (_Tp __t) { __is_derived_from_view_interface_fn(__t, __t); };
-  }
+  } // namespace __detail
 
   /// [range.view] The ranges::view_base type.
   struct view_base { };
@@ -689,11 +689,23 @@ namespace ranges
 concept common_range
   = range<_Tp> && same_as, sentinel_t<_Tp>>;
 
+  namespace __detail
+  {
+template
+  inline constexpr bool __is_initializer_list = false;
+
+template
+  inline constexpr bool __is_initializer_list> = 
true;
+  } // namespace __detail
+
   /// A range which can be safely converted to a view.
   template
 concept viewable_range = range<_Tp>
   && ((view> && 
constructible_from, _Tp>)
- || (!view> && borrowed_range<_Tp>));
+ || (!view>
+ && (is_lvalue_reference_v<_Tp>
+ || (movable>
+ && 
!__detail::__is_initializer_list>;
 
   // [range.iter.ops] range iterator operations
 
diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index ac85907f129..3e71ecb32b7 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -1144,6 +1144,87 @@ namespace views::__adaptor
   template
 inline constexpr bool enable_borrowed_range> = true;
 
+  template
+requires movable<_Range>
+  && (!__detail::__is_initializer_list>)
+class owning_view : public view_interface>
+{
+private:
+  _Range _M_r = _Range();
+
+public:
+  owning_view() requires default_initializable<_Range> = default;
+
+  constexpr
+  owning_view(_Range&& __t)
+  noexcept(is_nothrow_move_constructible_v<_Range>)
+   : _M_r(std::move(__t))
+  { }
+
+  owning_view(owning_view&&) = default;
+  owning_view& operator=(owning_view&&) = default;
+
+  constexpr _Range&
+  base() & noexcept
+  { return _M_r; }
+
+  constexpr const _Range&
+  base() const& noexcept
+  { return _M_r; }
+
+  constexpr _Range&&
+  base() && noexcept
+  { return std::move(_M_r); }
+
+  constexpr const _Range&&
+  base() const&& noexcept
+  { return std::move(_M_r); }
+
+  constexpr iterator_t<_Range>
+  begin()
+  { return ranges::begin(_M_r); }
+
+  constexpr sentinel_t<_Range>
+  end()
+  { return ranges::end(_M_r); }
+
+  constexpr auto
+  begin() const requires range
+  { return ranges::begin(_M_r); }
+
+  constexpr auto
+  end() const requires range
+  { return ranges::end(_M_r); }
+
+  constexpr bool
+  empty() requires requires { ranges::empty(_M_r); }
+  { return ranges::empty(_M_r); }
+
+  constexpr bool
+  empty() const requires requires { ranges::empty(_M_r); }
+  { return ranges::empty(_M_r); }
+
+  constexpr auto
+  size() requires sized_range<_Range>
+  { return ranges::size(_M_r); }
+
+  constexpr auto
+  size() const requires sized_range
+  { return ranges::size(_M_r); }
+
+  constexpr auto
+  data() requires contiguous_range<_Range>
+  { return ranges::data(_M_r); }
+
+  constexpr auto
+  data() const requires contiguous_range
+  { return ranges::data(_M_r); }
+};
+
+  template
+inline constexpr bool enable_borrowed_range>
+  = enable_borrowed_range<_Tp>;
+
   namespace views
   {
 namespace __detail
@@ 

[committed] c++: Add testcase for already fixed PR [PR85493]

2022-02-21 Thread Patrick Palka via Gcc-patches
The a1 and a2 case were fixed (by diagnosing the invalid expression)
with r11-434, and the a3 case with r8-7625.

PR c++/85493

gcc/testsuite/ChangeLog:

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

diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype80.C 
b/gcc/testsuite/g++.dg/cpp0x/decltype80.C
new file mode 100644
index 000..6ad140fe548
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/decltype80.C
@@ -0,0 +1,16 @@
+// PR c++/85493
+// { dg-do compile { target c++11 } }
+
+struct no_def {
+  no_def() = delete;
+};
+
+template
+int foo() = delete;
+
+template
+void test() {
+  decltype(no_def()) a1; // { dg-error "deleted" }
+  decltype(no_def(1,2,3)) a2; // { dg-error "no match" }
+  decltype(foo<>()) a3; // { dg-error "deleted" }
+}
-- 
2.35.1.225.ge2ac9141e6



[PATCH] c++: memory corruption during name lookup w/ modules [PR99479]

2022-02-17 Thread Patrick Palka via Gcc-patches
name_lookup::search_unqualified uses a statically allocated vector
in order to avoid repeated reallocation, under the assumption that
the function can't be called recursively.  With modules however,
this assumption turns out to be false, and search_unqualified can
be called recursively as demonstrated by testcase in comment #19
of PR99479[1] where the recursive call causes the vector to get
reallocated which invalidates the reference held by the parent call.

This patch makes search_unqualified instead use an auto_vec with 16
elements of internal storage (since with the various libraries I tested,
the size of the vector never exceeded 12).  In turn we can simplify the
API of subroutines to take the vector by reference and return void.

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

[1]: https://gcc.gnu.org/PR99479#c19

PR c++/99479

gcc/cp/ChangeLog:

* name-lookup.cc (name_lookup::using_queue): Change to an
auto_vec (with 16 elements of internal storage).
(name_lookup::queue_namespace): Change return type to void,
take queue parameter by reference and adjust function body
accordingly.
(name_lookup::do_queue_usings): Inline into ...
(name_lookup::queue_usings): ... here.  As in queue_namespace.
(name_lookup::search_unqualified): Don't make queue static,
assume its incoming length is 0, and adjust function body
accordingly.
---
 gcc/cp/name-lookup.cc | 62 +++
 1 file changed, 22 insertions(+), 40 deletions(-)

diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index 93c4eb7193b..5c965d6fba1 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -429,7 +429,7 @@ class name_lookup
 {
 public:
   typedef std::pair using_pair;
-  typedef vec using_queue;
+  typedef auto_vec using_queue;
 
 public:
   tree name;   /* The identifier being looked for.  */
@@ -528,16 +528,8 @@ private:
   bool search_usings (tree scope);
 
 private:
-  using_queue *queue_namespace (using_queue *queue, int depth, tree scope);
-  using_queue *do_queue_usings (using_queue *queue, int depth,
-   vec *usings);
-  using_queue *queue_usings (using_queue *queue, int depth,
-vec *usings)
-  {
-if (usings)
-  queue = do_queue_usings (queue, depth, usings);
-return queue;
-  }
+  void queue_namespace (using_queue& queue, int depth, tree scope);
+  void queue_usings (using_queue& queue, int depth, vec *usings);
 
 private:
   void add_fns (tree);
@@ -1084,39 +1076,35 @@ name_lookup::search_qualified (tree scope, bool usings)
 /* Add SCOPE to the unqualified search queue, recursively add its
inlines and those via using directives.  */
 
-name_lookup::using_queue *
-name_lookup::queue_namespace (using_queue *queue, int depth, tree scope)
+void
+name_lookup::queue_namespace (using_queue& queue, int depth, tree scope)
 {
   if (see_and_mark (scope))
-return queue;
+return;
 
   /* Record it.  */
   tree common = scope;
   while (SCOPE_DEPTH (common) > depth)
 common = CP_DECL_CONTEXT (common);
-  vec_safe_push (queue, using_pair (common, scope));
+  queue.safe_push (using_pair (common, scope));
 
   /* Queue its inline children.  */
   if (vec *inlinees = DECL_NAMESPACE_INLINEES (scope))
 for (unsigned ix = inlinees->length (); ix--;)
-  queue = queue_namespace (queue, depth, (*inlinees)[ix]);
+  queue_namespace (queue, depth, (*inlinees)[ix]);
 
   /* Queue its using targets.  */
-  queue = queue_usings (queue, depth, NAMESPACE_LEVEL 
(scope)->using_directives);
-
-  return queue;
+  queue_usings (queue, depth, NAMESPACE_LEVEL (scope)->using_directives);
 }
 
 /* Add the namespaces in USINGS to the unqualified search queue.  */
 
-name_lookup::using_queue *
-name_lookup::do_queue_usings (using_queue *queue, int depth,
- vec *usings)
+void
+name_lookup::queue_usings (using_queue& queue, int depth, vec 
*usings)
 {
-  for (unsigned ix = usings->length (); ix--;)
-queue = queue_namespace (queue, depth, (*usings)[ix]);
-
-  return queue;
+  if (usings)
+for (unsigned ix = usings->length (); ix--;)
+  queue_namespace (queue, depth, (*usings)[ix]);
 }
 
 /* Unqualified namespace lookup in SCOPE.
@@ -1128,15 +1116,12 @@ name_lookup::do_queue_usings (using_queue *queue, int 
depth,
 bool
 name_lookup::search_unqualified (tree scope, cp_binding_level *level)
 {
-  /* Make static to avoid continual reallocation.  We're not
- recursive.  */
-  static using_queue *queue = NULL;
+  using_queue queue;
   bool found = false;
-  int length = vec_safe_length (queue);
 
   /* Queue local using-directives.  */
   for (; level->kind != sk_namespace; level = level->level_chain)
-queue = queue_usings (queue, SCOPE_DEPTH (scope), level->using_directives);
+queue_usings (queue, SCOPE_DEPTH (scope), level->using_directives);
 
   for (; !found; 

[PATCH] c++: implicit 'this' in noexcept-spec within class tmpl [PR94944]

2022-02-17 Thread Patrick Palka via Gcc-patches
Here when instantiating the noexcept-spec we fail to resolve the
implicit object parameter for the call A::f() ultimately because
maybe_instantiate_noexcept sets current_class_ptr/ref to the dependent
'this' (of type B) rather than the specialized 'this' (of type B).
This ends up causing maybe_dummy_object (called from
finish_qualified_id_expr) to return a dummy object instead of 'this'.

This patch corrects this by making maybe_instantiate_noexcept always set
current_class_ptr/ref to the specialized 'this', consistent with what
tsubst_function_type does when substituting into a trailing return type.

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

PR c++/94944

gcc/cp/ChangeLog:

* pt.cc (maybe_instantiate_noexcept): For non-static member
functions, set current_class_ptr/ref to the specialized 'this'
instead.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/noexcept34.C: Adjusted expected diagnostics.
* g++.dg/cpp0x/noexcept75.C: New test.
---
 gcc/cp/pt.cc| 19 +++
 gcc/testsuite/g++.dg/cpp0x/noexcept34.C |  8 
 gcc/testsuite/g++.dg/cpp0x/noexcept75.C | 17 +
 3 files changed, 28 insertions(+), 16 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/noexcept75.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 6dda66081bd..a7a524fe9fc 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -26139,20 +26139,15 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t 
complain)
  push_deferring_access_checks (dk_no_deferred);
  input_location = DECL_SOURCE_LOCATION (fn);
 
- if (!DECL_LOCAL_DECL_P (fn))
+ if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)
+ && !DECL_LOCAL_DECL_P (fn))
{
  /* If needed, set current_class_ptr for the benefit of
-tsubst_copy/PARM_DECL.  The exception pattern will
-refer to the parm of the template, not the
-instantiation.  */
- tree tdecl = DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (fn));
- if (DECL_NONSTATIC_MEMBER_FUNCTION_P (tdecl))
-   {
- tree this_parm = DECL_ARGUMENTS (tdecl);
- current_class_ptr = NULL_TREE;
- current_class_ref = cp_build_fold_indirect_ref (this_parm);
- current_class_ptr = this_parm;
-   }
+tsubst_copy/PARM_DECL.  */
+ tree this_parm = DECL_ARGUMENTS (fn);
+ current_class_ptr = NULL_TREE;
+ current_class_ref = cp_build_fold_indirect_ref (this_parm);
+ current_class_ptr = this_parm;
}
 
  /* If this function is represented by a TEMPLATE_DECL, then
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept34.C 
b/gcc/testsuite/g++.dg/cpp0x/noexcept34.C
index dce35652ef5..86129e7a520 100644
--- a/gcc/testsuite/g++.dg/cpp0x/noexcept34.C
+++ b/gcc/testsuite/g++.dg/cpp0x/noexcept34.C
@@ -7,13 +7,13 @@ template struct A
 {
   constexpr int f () { return 0; }
   bool b = true;
-  void g () noexcept (f()) { } // { dg-error "use of parameter" }
-  void g2 () noexcept (this->f()) { } // { dg-error "use of parameter" }
+  void g () noexcept (f()) { } // { dg-error ".this. is not a constant" }
+  void g2 () noexcept (this->f()) { } // { dg-error ".this. is not a constant" 
}
   void g3 () noexcept (b) { } // { dg-error "use of .this. in a constant 
expression|use of parameter" }
   void g4 (int i) noexcept (i) { } // { dg-error "use of parameter" }
-  void g5 () noexcept (A::f()) { } // { dg-error "use of parameter" }
+  void g5 () noexcept (A::f()) { } // { dg-error ".this. is not a constant" }
   void g6 () noexcept (foo(b)) { } // { dg-error "use of .this. in a constant 
expression|use of parameter" }
-  void g7 () noexcept (int{f()}) { } // { dg-error "use of parameter" }
+  void g7 () noexcept (int{f()}) { } // { dg-error ".this. is not a constant" }
 };
 
 int main ()
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept75.C 
b/gcc/testsuite/g++.dg/cpp0x/noexcept75.C
new file mode 100644
index 000..d746f4768d0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/noexcept75.C
@@ -0,0 +1,17 @@
+// PR c++/94944
+// { dg-do compile { target c++11 } }
+
+template
+struct A {
+  void f();
+};
+
+template
+struct B : A {
+  void g() noexcept(noexcept(A::f()));
+};
+
+int main() {
+  B b;
+  b.g();
+}
-- 
2.35.1.129.gb80121027d



[PATCH] c++: double non-dep folding from finish_compound_literal [PR104565]

2022-02-16 Thread Patrick Palka via Gcc-patches
In finish_compound_literal, we perform non-dependent expr folding before
calling check_narrowing (ever since r9-5973).  But ever since r10-7096,
check_narrowing also performs non-dependent expr folding of its own.
This double folding cause tsubst to see non-templated trees during the
second folding, which causes a spurious error in the below testcase.

This patch removes this first folding operation; it now seems obviated
by the second one.

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

PR c++/104565

gcc/cp/ChangeLog:

* semantics.cc (finish_compound_literal): Don't perform
non-dependent expr folding before calling check_narrowing.

gcc/testsuite/ChangeLog:

* g++.dg/template/non-dependent22.C: New test.
---
 gcc/cp/semantics.cc | 10 +++---
 gcc/testsuite/g++.dg/template/non-dependent22.C | 12 
 2 files changed, 15 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/non-dependent22.C

diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 0cb17a6a8ab..114baa48710 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -3203,13 +3203,9 @@ finish_compound_literal (tree type, tree 
compound_literal,
 return error_mark_node;
   compound_literal = reshape_init (type, compound_literal, complain);
   if (SCALAR_TYPE_P (type)
-  && !BRACE_ENCLOSED_INITIALIZER_P (compound_literal))
-{
-  tree t = instantiate_non_dependent_expr_sfinae (compound_literal,
- complain);
-  if (!check_narrowing (type, t, complain))
-   return error_mark_node;
-}
+  && !BRACE_ENCLOSED_INITIALIZER_P (compound_literal)
+  && !check_narrowing (type, compound_literal, complain))
+return error_mark_node;
   if (TREE_CODE (type) == ARRAY_TYPE
   && TYPE_DOMAIN (type) == NULL_TREE)
 {
diff --git a/gcc/testsuite/g++.dg/template/non-dependent22.C 
b/gcc/testsuite/g++.dg/template/non-dependent22.C
new file mode 100644
index 000..83a6a13f15b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/non-dependent22.C
@@ -0,0 +1,12 @@
+// PR c++/104565
+// { dg-do compile { target c++11 } }
+
+struct apa {
+  constexpr int n() const { return 3; }
+};
+
+template
+int f() {
+  apa foo;
+  return int{foo.n()};  // no matching function for call to 'apa::n(apa*)'
+}
-- 
2.35.1.129.gb80121027d



Re: [PATCH] c++: return-type-req in constraint using only outer tparms [PR104527]

2022-02-16 Thread Patrick Palka via Gcc-patches
On Tue, 15 Feb 2022, Jason Merrill wrote:

> On 2/14/22 11:32, Patrick Palka wrote:
> > Here the template context for the atomic constraint has two levels of
> > template arguments, but since it depends only on the innermost argument
> > T we use a single-level argument vector during substitution into the
> > constraint (built by get_mapped_args).  We eventually pass this vector
> > to do_auto_deduction as part of checking the return-type-requirement
> > inside the atom, but do_auto_deduction expects outer_targs to be a full
> > set of arguments for sake of satisfaction.
> 
> Could we note the current number of levels in the map and use that in
> get_mapped_args instead of the highest level parameter we happened to use?

Ah yeah, that seems to work nicely.  IIUC it should suffice to remember
whether the atomic constraint expression came from a concept definition.
If it did, then the depth of the argument vector returned by
get_mapped_args must be one, otherwise (as in the testcase) it must be
the same as the template depth of the constrained entity, which is the
depth of ARGS.

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

-- >8 --

Subject: [PATCH] c++: return-type-req in constraint using only outer tparms
 [PR104527]

Here the template context for the atomic constraint has two levels of
template parameters, but since it depends only on the innermost parameter
T we use a single-level argument vector (built by get_mapped_args) during
substitution into the atom.  We eventually pass this vector to
do_auto_deduction as part of checking the return-type-requirement within
the atom, but do_auto_deduction expects outer_targs to be a full set of
arguments for sake of satisfaction.

This patch fixes this by making get_mapped_args always return an
argument vector whose depth corresponds to the template depth of the
context in which the atomic constraint expression was written, instead
of the highest parameter level that the expression happens to use.

PR c++/104527

gcc/cp/ChangeLog:

* constraint.cc (normalize_atom): Set
ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P appropriately.
(get_mapped_args):  Make static, adjust parameters.  Always
return a vector whose depth corresponds to the template depth of
the context of the atomic constraint expression.  Micro-optimize
by passing false as exact to safe_grow_cleared and by collapsing
a multi-level depth-one argument vector.
(satisfy_atom): Adjust call to get_mapped_args and
diagnose_atomic_constraint.
(diagnose_atomic_constraint): Replace map parameter with an args
parameter.
* cp-tree.h (ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P): Define.
(get_mapped_args): Remove declaration.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts-return-req4.C: New test.
---
 gcc/cp/constraint.cc  | 64 +++
 gcc/cp/cp-tree.h  |  7 +-
 .../g++.dg/cpp2a/concepts-return-req4.C   | 24 +++
 3 files changed, 69 insertions(+), 26 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 12db7e5cf14..306e28955c6 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -764,6 +764,8 @@ normalize_atom (tree t, tree args, norm_info info)
   tree ci = build_tree_list (t, info.context);
 
   tree atom = build1 (ATOMIC_CONSTR, ci, map);
+  if (info.in_decl && concept_definition_p (info.in_decl))
+ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (atom) = true;
   if (!info.generate_diagnostics ())
 {
   /* Cache the ATOMIC_CONSTRs that we return, so that sat_hasher::equal
@@ -2826,33 +2828,37 @@ satisfaction_value (tree t)
 return boolean_true_node;
 }
 
-/* Build a new template argument list with template arguments corresponding
-   to the parameters used in an atomic constraint.  */
+/* Build a new template argument vector according to the parameter
+   mapping of the atomic constraint T, using arguments from ARGS.  */
 
-tree
-get_mapped_args (tree map)
+static tree
+get_mapped_args (tree t, tree args)
 {
+  tree map = ATOMIC_CONSTR_MAP (t);
+
   /* No map, no arguments.  */
   if (!map)
 return NULL_TREE;
 
-  /* Find the mapped parameter with the highest level.  */
-  int count = 0;
-  for (tree p = map; p; p = TREE_CHAIN (p))
-{
-  int level;
-  int index;
-  template_parm_level_and_index (TREE_VALUE (p), , );
-  if (level > count)
-count = level;
-}
+  /* Determine the depth of the resulting argument vector.  */
+  int depth;
+  if (ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (t))
+/* The expression of this atomic constraint comes from a concept 
definition,
+   whose template depth is always one, so the resulting argument vector
+   will also have dept

Re: [PATCH] c++: NON_DEPENDENT_EXPR is not potentially constant [PR104507]

2022-02-16 Thread Patrick Palka via Gcc-patches
On Tue, 15 Feb 2022, Jason Merrill wrote:

> On 2/15/22 17:00, Patrick Palka wrote:
> > On Tue, 15 Feb 2022, Jason Merrill wrote:
> > 
> > > On 2/15/22 15:13, Patrick Palka wrote:
> > > > On Tue, 15 Feb 2022, Patrick Palka wrote:
> > > > 
> > > > > Here we're crashing from potential_constant_expression because it
> > > > > tries
> > > > > to perform trial evaluation of the first operand '(bool)__r' of the
> > > > > conjunction (which is overall wrapped in a NON_DEPENDENT_EXPR), but
> > > > > cxx_eval_constant_expression ICEs on unhandled trees (of which
> > > > > CAST_EXPR
> > > > > is one).
> > > > > 
> > > > > Since cxx_eval_constant_expression always treats NON_DEPENDENT_EXPR
> > > > > as non-constant, and since NON_DEPENDENT_EXPR is also opaque to
> > > > > instantiate_non_dependent_expr, it seems futile to have p_c_e_1 ever
> > > > > return true for NON_DEPENDENT_EXPR, so let's just instead return false
> > > > > and avoid recursing.
> > > 
> > > Well, in a template we use pce1 to decide whether to complain about
> > > something
> > > that needs to be constant but can't be.  We aren't trying to get a value
> > > yet.
> > 
> > Makes sense.. though for NON_DEPENDENT_EXPR in particular, ISTM this
> > tree is always used in a context where a constant expression isn't
> > required, e.g. in the build_x_* functions.
> 
> Fair enough.  The patch is OK with a comment to that effect.

Thanks, I committed the following as r12-7264:

-- >8 --

Subject: [PATCH] c++: treat NON_DEPENDENT_EXPR as not potentially constant
 [PR104507]

Here we're crashing from potential_constant_expression because it tries
to perform trial evaluation of the first operand '(bool)__r' of the
conjunction (which is overall wrapped in a NON_DEPENDENT_EXPR), but
cxx_eval_constant_expression ICEs on unsupported trees (of which CAST_EXPR
is one).  The sequence of events is:

  1. build_non_dependent_expr for the array subscript yields
 NON_DEPENDENT_EXPR<<<(bool)__r && __s>>> ? 1 : 2
  2. cp_build_array_ref calls fold_non_dependent_expr on this subscript
 (after this point, processing_template_decl is cleared)
  3. during which, the COND_EXPR case of tsubst_copy_and_build calls
 fold_non_dependent_expr on the first operand
  4. during which, we crash from p_c_e_1 because it attempts trial
 evaluation of the CAST_EXPR '(bool)__r'.

Note that even if this crash didn't happen, fold_non_dependent_expr
from cp_build_array_ref would still ultimately be one big no-op here
since neither constexpr evaluation nor tsubst handle NON_DEPENDENT_EXPR.

In light of this and of the observation that we should never see
NON_DEPENDENT_EXPR in a context where a constant expression is needed
(it's used primarily in the build_x_* family of functions), it seems
futile for p_c_e_1 to ever return true for NON_DEPENDENT_EXPR.  And the
otherwise inconsistent handling of NON_DEPENDENT_EXPR between p_c_e_1,
cxx_evaluate_constexpr_expression and tsubst apparently leads to weird
bugs such as this one.

PR c++/104507

gcc/cp/ChangeLog:

* constexpr.cc (potential_constant_expression_1)
: Return false instead of recursing.
Assert tf_error isn't set.

gcc/testsuite/ChangeLog:

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

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 7274c3b760e..4716694cb71 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -9065,6 +9065,14 @@ potential_constant_expression_1 (tree t, bool want_rval, 
bool strict, bool now,
 case BIND_EXPR:
   return RECUR (BIND_EXPR_BODY (t), want_rval);
 
+case NON_DEPENDENT_EXPR:
+  /* Treat NON_DEPENDENT_EXPR as non-constant: it's not handled by
+constexpr evaluation or tsubst, so fold_non_dependent_expr can't
+do anything useful with it.  And we shouldn't see it in a context
+where a constant expression is strictly required, hence the assert.  */
+  gcc_checking_assert (!(flags & tf_error));
+  return false;
+
 case CLEANUP_POINT_EXPR:
 case MUST_NOT_THROW_EXPR:
 case TRY_CATCH_EXPR:
@@ -9072,7 +9080,6 @@ potential_constant_expression_1 (tree t, bool want_rval, 
bool strict, bool now,
 case EH_SPEC_BLOCK:
 case EXPR_STMT:
 case PAREN_EXPR:
-case NON_DEPENDENT_EXPR:
   /* For convenience.  */
 case LOOP_EXPR:
 case EXIT_EXPR:
diff --git a/gcc/testsuite/g++.dg/templ

Re: [PATCH] c++: NON_DEPENDENT_EXPR is not potentially constant [PR104507]

2022-02-15 Thread Patrick Palka via Gcc-patches
On Tue, 15 Feb 2022, Jason Merrill wrote:

> On 2/15/22 15:13, Patrick Palka wrote:
> > On Tue, 15 Feb 2022, Patrick Palka wrote:
> > 
> > > Here we're crashing from potential_constant_expression because it tries
> > > to perform trial evaluation of the first operand '(bool)__r' of the
> > > conjunction (which is overall wrapped in a NON_DEPENDENT_EXPR), but
> > > cxx_eval_constant_expression ICEs on unhandled trees (of which CAST_EXPR
> > > is one).
> > > 
> > > Since cxx_eval_constant_expression always treats NON_DEPENDENT_EXPR
> > > as non-constant, and since NON_DEPENDENT_EXPR is also opaque to
> > > instantiate_non_dependent_expr, it seems futile to have p_c_e_1 ever
> > > return true for NON_DEPENDENT_EXPR, so let's just instead return false
> > > and avoid recursing.
> 
> Well, in a template we use pce1 to decide whether to complain about something
> that needs to be constant but can't be.  We aren't trying to get a value yet.

Makes sense.. though for NON_DEPENDENT_EXPR in particular, ISTM this
tree is always used in a context where a constant expression isn't
required, e.g. in the build_x_* functions.

And if something is required to be a constant expression and we're
inside a template, then it seems at that point we're dealing with the
final templated form of that thing (which doesn't contain
NON_DEPENDENT_EXPR), which I suppose explains why the patch can get away
with asserting !(flags & tf_error) inside the NON_DEPENDENT_EXPR case of
p_c_e_1.

So I guess I don't fully understand the purpose of NON_DEPENDENT_EXPR
or how it should interact with fold_non_dependent_expr and constant
evaluation...

> 
> Actually, why are we seeing a NON_DEPENDENT_EXPR here?  Did it leak into the
> AST somehow?  They should all be temporary within build_x_whatever functions.

Hmm yes, kind of.  The unusual thing about this testcase is that
build_non_dependent_expr (called from grok_array_decl) for the
COND_EXPR

  (bool)__r && __s ? 1 : 2

wraps only the condition operand, yielding

  NON_DEPENDENT_EXPR<<<(bool)__r && __s>>> ? 1 : 2// #1

rather than wrapping the whole thing i.e.

  NON_DEPENDENT_EXPR<<<(bool)__r && __s ? 1 : 2>>>// #2

cp_build_array_ref then tries to speculatively fold the non-dependent #1
as a whole, during which the COND_EXPR case of tsubst_copy_and_build
tries to speculative fold #1's condition NON_DEPENDENT_EXPR<<<(bool)__r && 
__s>>>
on its own, which ends in a crash from p_c_e_1 because at this point
processing_template_decl is cleared so p_c_e_1 attempts trial evaluation
of the CAST_EXPR (bool)__r.

If instead build_non_dependent_expr yielded #2, speculative folding of
#2 as a whole just yield #2 since tsubst doesn't look through
NON_DEPENDENT_EXPR.

> 
> > > Alternatively p_c_e_1 could continue to recurse into NON_DEPENDENT_EXPR,
> > > but with trial evaluation disabled by setting processing_template_decl,
> > > but as mentioned it seems pointless for p_c_e_1 to ever return true for
> > > NON_DEPENDENT_EXPR.
> > ... Since we're not issuing a diagnostic in this case, I suppose we should
> > also assert that tf_error isn't set.  Bootstrapped and regtested on
> > x86_64-pc-linux-gnu.
> > 
> > -- >8 --
> > 
> > PR c++/104507
> > 
> > gcc/cp/ChangeLog:
> > 
> > * constexpr.cc (potential_constant_expression_1)
> > : Return false instead of recursing.
> > Assert tf_error isn't set.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/template/non-dependent21.C: New test.
> > ---
> >   gcc/cp/constexpr.cc | 5 -
> >   gcc/testsuite/g++.dg/template/non-dependent21.C | 9 +
> >   2 files changed, 13 insertions(+), 1 deletion(-)
> >   create mode 100644 gcc/testsuite/g++.dg/template/non-dependent21.C
> > 
> > diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> > index 7274c3b760e..b363ef08411 100644
> > --- a/gcc/cp/constexpr.cc
> > +++ b/gcc/cp/constexpr.cc
> > @@ -9065,6 +9065,10 @@ potential_constant_expression_1 (tree t, bool
> > want_rval, bool strict, bool now,
> >   case BIND_EXPR:
> > return RECUR (BIND_EXPR_BODY (t), want_rval);
> >   +case NON_DEPENDENT_EXPR:
> > +  gcc_checking_assert (!(flags & tf_error));
> > +  return false;
> > +
> >   case CLEANUP_POINT_EXPR:
> >   case MUST_NOT_THROW_EXPR:
> >   case TRY_CATCH_EXPR:
> > @@ -9072,7 +9076,6 @@ potential_constant_expression_1 (tree t, bool
> > want_rval, bool strict, bool now,
> >   case EH_SPEC_BLOCK:
> >   case

Re: [PATCH] c++: NON_DEPENDENT_EXPR is not potentially constant [PR104507]

2022-02-15 Thread Patrick Palka via Gcc-patches
On Tue, 15 Feb 2022, Patrick Palka wrote:

> Here we're crashing from potential_constant_expression because it tries
> to perform trial evaluation of the first operand '(bool)__r' of the
> conjunction (which is overall wrapped in a NON_DEPENDENT_EXPR), but
> cxx_eval_constant_expression ICEs on unhandled trees (of which CAST_EXPR
> is one).
> 
> Since cxx_eval_constant_expression always treats NON_DEPENDENT_EXPR
> as non-constant, and since NON_DEPENDENT_EXPR is also opaque to
> instantiate_non_dependent_expr, it seems futile to have p_c_e_1 ever
> return true for NON_DEPENDENT_EXPR, so let's just instead return false
> and avoid recursing.
> 
> Alternatively p_c_e_1 could continue to recurse into NON_DEPENDENT_EXPR,
> but with trial evaluation disabled by setting processing_template_decl,
> but as mentioned it seems pointless for p_c_e_1 to ever return true for
> NON_DEPENDENT_EXPR.
> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk and perhaps 10/11?
> 
>   PR c++/104507
> 
> gcc/cp/ChangeLog:
> 
>   * constexpr.cc (potential_constant_expression_1)
>   : Return false rather than recursing.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/template/non-dependent21.C: New test.
> ---
>  gcc/cp/constexpr.cc | 4 +++-
>  gcc/testsuite/g++.dg/template/non-dependent21.C | 9 +
>  2 files changed, 12 insertions(+), 1 deletion(-)
>  create mode 100644 gcc/testsuite/g++.dg/template/non-dependent21.C
> 
> diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> index 7274c3b760e..c0523551f7b 100644
> --- a/gcc/cp/constexpr.cc
> +++ b/gcc/cp/constexpr.cc
> @@ -9065,6 +9065,9 @@ potential_constant_expression_1 (tree t, bool 
> want_rval, bool strict, bool now,
>  case BIND_EXPR:
>return RECUR (BIND_EXPR_BODY (t), want_rval);
>  
> +case NON_DEPENDENT_EXPR:
> +  return false;

Since we're not issuing a diagnostic in this case, I suppose we should
also assert that tf_error isn't set.  Bootstrapped and regtested on
x86_64-pc-linux-gnu.

-- >8 --

PR c++/104507

gcc/cp/ChangeLog:

* constexpr.cc (potential_constant_expression_1)
: Return false instead of recursing.
Assert tf_error isn't set.

gcc/testsuite/ChangeLog:

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

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 7274c3b760e..b363ef08411 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -9065,6 +9065,10 @@ potential_constant_expression_1 (tree t, bool want_rval, 
bool strict, bool now,
 case BIND_EXPR:
   return RECUR (BIND_EXPR_BODY (t), want_rval);
 
+case NON_DEPENDENT_EXPR:
+  gcc_checking_assert (!(flags & tf_error));
+  return false;
+
 case CLEANUP_POINT_EXPR:
 case MUST_NOT_THROW_EXPR:
 case TRY_CATCH_EXPR:
@@ -9072,7 +9076,6 @@ potential_constant_expression_1 (tree t, bool want_rval, 
bool strict, bool now,
 case EH_SPEC_BLOCK:
 case EXPR_STMT:
 case PAREN_EXPR:
-case NON_DEPENDENT_EXPR:
   /* For convenience.  */
 case LOOP_EXPR:
 case EXIT_EXPR:
diff --git a/gcc/testsuite/g++.dg/template/non-dependent21.C 
b/gcc/testsuite/g++.dg/template/non-dependent21.C
new file mode 100644
index 000..89900837b8b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/non-dependent21.C
@@ -0,0 +1,9 @@
+// PR c++/104507
+
+extern const char *_k_errmsg[];
+
+template
+const char* DoFoo(int __r, int __s) {
+  const char* n = _k_errmsg[(bool)__r && __s ? 1 : 2];
+  return n;
+}
-- 
2.35.1.129.gb80121027d



[PATCH] c++: NON_DEPENDENT_EXPR is not potentially constant [PR104507]

2022-02-15 Thread Patrick Palka via Gcc-patches
Here we're crashing from potential_constant_expression because it tries
to perform trial evaluation of the first operand '(bool)__r' of the
conjunction (which is overall wrapped in a NON_DEPENDENT_EXPR), but
cxx_eval_constant_expression ICEs on unhandled trees (of which CAST_EXPR
is one).

Since cxx_eval_constant_expression always treats NON_DEPENDENT_EXPR
as non-constant, and since NON_DEPENDENT_EXPR is also opaque to
instantiate_non_dependent_expr, it seems futile to have p_c_e_1 ever
return true for NON_DEPENDENT_EXPR, so let's just instead return false
and avoid recursing.

Alternatively p_c_e_1 could continue to recurse into NON_DEPENDENT_EXPR,
but with trial evaluation disabled by setting processing_template_decl,
but as mentioned it seems pointless for p_c_e_1 to ever return true for
NON_DEPENDENT_EXPR.

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

PR c++/104507

gcc/cp/ChangeLog:

* constexpr.cc (potential_constant_expression_1)
: Return false rather than recursing.

gcc/testsuite/ChangeLog:

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

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 7274c3b760e..c0523551f7b 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -9065,6 +9065,9 @@ potential_constant_expression_1 (tree t, bool want_rval, 
bool strict, bool now,
 case BIND_EXPR:
   return RECUR (BIND_EXPR_BODY (t), want_rval);
 
+case NON_DEPENDENT_EXPR:
+  return false;
+
 case CLEANUP_POINT_EXPR:
 case MUST_NOT_THROW_EXPR:
 case TRY_CATCH_EXPR:
@@ -9072,7 +9075,6 @@ potential_constant_expression_1 (tree t, bool want_rval, 
bool strict, bool now,
 case EH_SPEC_BLOCK:
 case EXPR_STMT:
 case PAREN_EXPR:
-case NON_DEPENDENT_EXPR:
   /* For convenience.  */
 case LOOP_EXPR:
 case EXIT_EXPR:
diff --git a/gcc/testsuite/g++.dg/template/non-dependent21.C 
b/gcc/testsuite/g++.dg/template/non-dependent21.C
new file mode 100644
index 000..89900837b8b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/non-dependent21.C
@@ -0,0 +1,9 @@
+// PR c++/104507
+
+extern const char *_k_errmsg[];
+
+template
+const char* DoFoo(int __r, int __s) {
+  const char* n = _k_errmsg[(bool)__r && __s ? 1 : 2];
+  return n;
+}
-- 
2.35.1.129.gb80121027d



Re: [PATCH] c++: return-type-req in constraint using only outer tparms [PR104527]

2022-02-14 Thread Patrick Palka via Gcc-patches
On Mon, 14 Feb 2022, Patrick Palka wrote:

> Here the template context for the atomic constraint has two levels of
> template arguments, but since it depends only on the innermost argument
> T we use a single-level argument vector during substitution into the
> constraint (built by get_mapped_args).  We eventually pass this vector
> to do_auto_deduction as part of checking the return-type-requirement
> inside the atom, but do_auto_deduction expects outer_targs to be a full
> set of arguments for sake of satisfaction.
> 
> do_auto_deduction has a workaround in place to compensate for callers
> that pass only the innermost arguments as outer_targs, but here we're
> passing the _outermost_ arguments.  Since the former situation should
> now (after r12-7101) only occur with adc_unify callers and the latter

Whoops, this should be r12-6919 (after which we pass outer_targs
appropriately during adc_variable_type deduction of non-function-scope
variables), not r12-7101, sorry about that.

> only with adc_requirement callers, this patch conditions the existing
> workaround according to the auto_deduction_context: if the context is
> adc_requirement, we add dummy innermost levels, otherwise we add dummy
> outermost levels as before and also assert that the context is adc_unify.
> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu and tested on cmcstl2
> and range-v3, does this look OK for trunk?
> 
>   PR c++/104527
> 
> gcc/cp/ChangeLog:
> 
>   * pt.cc (do_auto_deduction): When template argument levels are
>   missing from outer_targs, fill in the innermost rather than the
>   outermost levels with dummy args if the context is
>   adc_requirement, otherwise also assert that the context is
>   adc_unify.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp2a/concepts-return-req4.C: New test.
> ---
>  gcc/cp/pt.cc  | 28 +--
>  .../g++.dg/cpp2a/concepts-return-req4.C   | 24 
>  2 files changed, 44 insertions(+), 8 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C
> 
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 1b18e2a7787..4ff2710b8ba 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -30215,20 +30215,32 @@ do_auto_deduction (tree type, tree init, tree 
> auto_node,
>  
>tree full_targs = add_to_template_args (outer_targs, targs);
>  
> -  /* HACK: Compensate for callers not always communicating all levels of
> -  outer template arguments by filling in the outermost missing levels
> -  with dummy levels before checking satisfaction.  We'll still crash
> -  if the constraint depends on a template argument belonging to one of
> -  these missing levels, but this hack otherwise allows us to handle a
> -  large subset of possible constraints (including all non-dependent
> -  constraints).  */
>if (int missing_levels = (TEMPLATE_TYPE_ORIG_LEVEL (auto_node)
>   - TMPL_ARGS_DEPTH (full_targs)))
>   {
> tree dummy_levels = make_tree_vec (missing_levels);
> for (int i = 0; i < missing_levels; ++i)
>   TREE_VEC_ELT (dummy_levels, i) = make_tree_vec (0);
> -   full_targs = add_to_template_args (dummy_levels, full_targs);
> +   if (context == adc_requirement)
> + /* We're checking a requires-expr's return-type-requirement that's
> +part of an atomic constraint that doesn't depend on any innermost
> +template arguments, so OUTER_TARGS (built by get_mapped_args) is
> +missing at least one innermost level.  Fill in the innermost
> +levels of OUTER_TARGS with dummy levels.  */
> + full_targs = add_to_template_args
> +   (add_to_template_args (outer_targs, dummy_levels), targs);
> +   else
> + {
> +   /* Otherwise, fill in the _outermost_ levels with dummy levels.
> +  This compensates for adc_unify callers that only pass the
> +  innermost level of template arguments as OUTER_TARGS.  We'll
> +  still crash if the constraint depends on a template argument
> +  belonging to one of these missing levels, but this hack
> +  otherwise allows us to handle a large subset of possible
> +  constraints (including all non-dependent constraints).  */
> +   gcc_checking_assert (context == adc_unify);
> +   full_targs = add_to_template_args (dummy_levels, full_targs);
> + }
>   }
>  
>if (!constraints_satisfied_p (auto_node, full_targs))
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C 
> b/gcc/testsuite/g++.dg/cpp2a/concepts-return-r

[PATCH] c++: return-type-req in constraint using only outer tparms [PR104527]

2022-02-14 Thread Patrick Palka via Gcc-patches
Here the template context for the atomic constraint has two levels of
template arguments, but since it depends only on the innermost argument
T we use a single-level argument vector during substitution into the
constraint (built by get_mapped_args).  We eventually pass this vector
to do_auto_deduction as part of checking the return-type-requirement
inside the atom, but do_auto_deduction expects outer_targs to be a full
set of arguments for sake of satisfaction.

do_auto_deduction has a workaround in place to compensate for callers
that pass only the innermost arguments as outer_targs, but here we're
passing the _outermost_ arguments.  Since the former situation should
now (after r12-7101) only occur with adc_unify callers and the latter
only with adc_requirement callers, this patch conditions the existing
workaround according to the auto_deduction_context: if the context is
adc_requirement, we add dummy innermost levels, otherwise we add dummy
outermost levels as before and also assert that the context is adc_unify.

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

PR c++/104527

gcc/cp/ChangeLog:

* pt.cc (do_auto_deduction): When template argument levels are
missing from outer_targs, fill in the innermost rather than the
outermost levels with dummy args if the context is
adc_requirement, otherwise also assert that the context is
adc_unify.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts-return-req4.C: New test.
---
 gcc/cp/pt.cc  | 28 +--
 .../g++.dg/cpp2a/concepts-return-req4.C   | 24 
 2 files changed, 44 insertions(+), 8 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 1b18e2a7787..4ff2710b8ba 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -30215,20 +30215,32 @@ do_auto_deduction (tree type, tree init, tree 
auto_node,
 
   tree full_targs = add_to_template_args (outer_targs, targs);
 
-  /* HACK: Compensate for callers not always communicating all levels of
-outer template arguments by filling in the outermost missing levels
-with dummy levels before checking satisfaction.  We'll still crash
-if the constraint depends on a template argument belonging to one of
-these missing levels, but this hack otherwise allows us to handle a
-large subset of possible constraints (including all non-dependent
-constraints).  */
   if (int missing_levels = (TEMPLATE_TYPE_ORIG_LEVEL (auto_node)
- TMPL_ARGS_DEPTH (full_targs)))
{
  tree dummy_levels = make_tree_vec (missing_levels);
  for (int i = 0; i < missing_levels; ++i)
TREE_VEC_ELT (dummy_levels, i) = make_tree_vec (0);
- full_targs = add_to_template_args (dummy_levels, full_targs);
+ if (context == adc_requirement)
+   /* We're checking a requires-expr's return-type-requirement that's
+  part of an atomic constraint that doesn't depend on any innermost
+  template arguments, so OUTER_TARGS (built by get_mapped_args) is
+  missing at least one innermost level.  Fill in the innermost
+  levels of OUTER_TARGS with dummy levels.  */
+   full_targs = add_to_template_args
+ (add_to_template_args (outer_targs, dummy_levels), targs);
+ else
+   {
+ /* Otherwise, fill in the _outermost_ levels with dummy levels.
+This compensates for adc_unify callers that only pass the
+innermost level of template arguments as OUTER_TARGS.  We'll
+still crash if the constraint depends on a template argument
+belonging to one of these missing levels, but this hack
+otherwise allows us to handle a large subset of possible
+constraints (including all non-dependent constraints).  */
+ gcc_checking_assert (context == adc_unify);
+ full_targs = add_to_template_args (dummy_levels, full_targs);
+   }
}
 
   if (!constraints_satisfied_p (auto_node, full_targs))
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C
new file mode 100644
index 000..471946bc8eb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C
@@ -0,0 +1,24 @@
+// PR c++/104527
+// { dg-do compile { target c++20 } }
+
+template
+concept is_same = __is_same(T, U);
+
+template
+struct A {
+  template
+requires requires { { 0 } -> is_same; }
+  struct B {};
+
+  template
+requires requires { { 1 } -> is_same; }
+  static void f();
+};
+
+A::B<> a1;
+A::B<> a2; // { dg-error "constraint" }
+
+int main() {
+  A::f();
+  A::f(); // { dg-error "no match" }
+}
-- 
2.35.1.102.g2b9c120970



Re: [PATCH] libstdc++: Back out some changes in P2325R3 backport [PR103904]

2022-02-11 Thread Patrick Palka via Gcc-patches
On Fri, 11 Feb 2022, Patrick Palka wrote:

> In the P2325R3 backport r11-9555 the relaxation of the constraints on
> the partial specialization of __box (which is semantically equivalent to
> the primary template, only more space efficient) means some
> specializations of __box will now use the partial specialization instead
> of the primary template, which (IIUC) constitutes an ABI change unsuitable
> for a release branch.  This patch reverts this constraint change, which
> isn't needed for correctness anyway.
> 
> Similarly the change to use __non_propagating_cache for the data member
> split_view::_M_current (so that it's always default-initializable) also
> constitutes an unsuitable ABI change.  This patch reverts this change
> too, and instead further constrains split_view's default constructor to
> require that we can default-initialize _M_current.

Forgot to clarify that this is for the 11 branch, tested on
x86_64-pc-linux-gnu.  Does this look reasonable?  I noticed these
issues while backporting r11-9555 to the 10 branch, which doesn't have
__non_propagating_cache or the partial specialization of __box.

> 
>   PR libstdc++/103904
> 
> libstdc++-v3/ChangeLog:
> 
>   * include/std/ranges (__detail::__box): Revert r11-9555 changes
>   to the constraints on the partial specialization and the
>   now-unnecessary member additions.
>   (__detail::__non_propagating_cache::operator=): Remove
>   now-unused overload added by r11-9555.
>   (split_view::_OuterIter::__current): Adjust after reverting the
>   r11-9555 change to the type of _M_current.
>   (split_view::_M_current): Revert r11-9555 change to its type.
>   (split_view::split_view): Constrain the default ctor further.
>   * testsuite/std/ranges/adaptors/detail/copyable_box.cc: Disable
>   now-irrelevant test for the r11-9555 changes to the partial
>   specialization of __box.
> ---
>  libstdc++-v3/include/std/ranges   | 54 +++
>  .../ranges/adaptors/detail/copyable_box.cc|  4 ++
>  2 files changed, 10 insertions(+), 48 deletions(-)
> 
> diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
> index 03c6275801f..bf31e4be500 100644
> --- a/libstdc++-v3/include/std/ranges
> +++ b/libstdc++-v3/include/std/ranges
> @@ -144,8 +144,7 @@ namespace ranges
>  // std::optional.  It provides just the subset of the primary template's
>  // API that we currently use.
>  template<__boxable _Tp>
> -  requires copyable<_Tp> || (is_nothrow_move_constructible_v<_Tp>
> -  && is_nothrow_copy_constructible_v<_Tp>)
> +  requires copyable<_Tp>
>struct __box<_Tp>
>{
>private:
> @@ -174,38 +173,6 @@ namespace ranges
> : _M_value(std::forward<_Args>(__args)...)
> { }
>  
> - __box(const __box&) = default;
> - __box(__box&&) = default;
> - __box& operator=(const __box&) requires copyable<_Tp> = default;
> - __box& operator=(__box&&) requires copyable<_Tp> = default;
> -
> - // When _Tp is nothrow_copy_constructible but not copy_assignable,
> - // copy assignment is implemented via destroy-then-copy-construct.
> - constexpr __box&
> - operator=(const __box& __that) noexcept
> - {
> -   static_assert(is_nothrow_copy_constructible_v<_Tp>);
> -   if (this != std::__addressof(__that))
> - {
> -   _M_value.~_Tp();
> -   std::construct_at(std::__addressof(_M_value), *__that);
> - }
> -   return *this;
> - }
> -
> - // Likewise for move assignment.
> - constexpr __box&
> - operator=(__box&& __that) noexcept
> - {
> -   static_assert(is_nothrow_move_constructible_v<_Tp>);
> -   if (this != std::__addressof(__that))
> - {
> -   _M_value.~_Tp();
> -   std::construct_at(std::__addressof(_M_value), std::move(*__that));
> - }
> -   return *this;
> - }
> -
>   constexpr bool
>   has_value() const noexcept
>   { return true; };
> @@ -1180,16 +1147,6 @@ namespace views::__adaptor
> return *this;
>   }
>  
> - constexpr __non_propagating_cache&
> - operator=(_Tp __val)
> - {
> -   this->_M_reset();
> -   std::construct_at(std::__addressof(this->_M_payload._M_payload),
> - std::in_place, std::move(__val));
> -   this->_M_payload._M_engaged = true;
> -   return *this;
> - }
> -
>   constexpr _Tp&
>   operato

[PATCH] libstdc++: Back out some changes in P2325R3 backport [PR103904]

2022-02-11 Thread Patrick Palka via Gcc-patches
In the P2325R3 backport r11-9555 the relaxation of the constraints on
the partial specialization of __box (which is semantically equivalent to
the primary template, only more space efficient) means some
specializations of __box will now use the partial specialization instead
of the primary template, which (IIUC) constitutes an ABI change unsuitable
for a release branch.  This patch reverts this constraint change, which
isn't needed for correctness anyway.

Similarly the change to use __non_propagating_cache for the data member
split_view::_M_current (so that it's always default-initializable) also
constitutes an unsuitable ABI change.  This patch reverts this change
too, and instead further constrains split_view's default constructor to
require that we can default-initialize _M_current.

PR libstdc++/103904

libstdc++-v3/ChangeLog:

* include/std/ranges (__detail::__box): Revert r11-9555 changes
to the constraints on the partial specialization and the
now-unnecessary member additions.
(__detail::__non_propagating_cache::operator=): Remove
now-unused overload added by r11-9555.
(split_view::_OuterIter::__current): Adjust after reverting the
r11-9555 change to the type of _M_current.
(split_view::_M_current): Revert r11-9555 change to its type.
(split_view::split_view): Constrain the default ctor further.
* testsuite/std/ranges/adaptors/detail/copyable_box.cc: Disable
now-irrelevant test for the r11-9555 changes to the partial
specialization of __box.
---
 libstdc++-v3/include/std/ranges   | 54 +++
 .../ranges/adaptors/detail/copyable_box.cc|  4 ++
 2 files changed, 10 insertions(+), 48 deletions(-)

diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 03c6275801f..bf31e4be500 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -144,8 +144,7 @@ namespace ranges
 // std::optional.  It provides just the subset of the primary template's
 // API that we currently use.
 template<__boxable _Tp>
-  requires copyable<_Tp> || (is_nothrow_move_constructible_v<_Tp>
-&& is_nothrow_copy_constructible_v<_Tp>)
+  requires copyable<_Tp>
   struct __box<_Tp>
   {
   private:
@@ -174,38 +173,6 @@ namespace ranges
  : _M_value(std::forward<_Args>(__args)...)
  { }
 
-   __box(const __box&) = default;
-   __box(__box&&) = default;
-   __box& operator=(const __box&) requires copyable<_Tp> = default;
-   __box& operator=(__box&&) requires copyable<_Tp> = default;
-
-   // When _Tp is nothrow_copy_constructible but not copy_assignable,
-   // copy assignment is implemented via destroy-then-copy-construct.
-   constexpr __box&
-   operator=(const __box& __that) noexcept
-   {
- static_assert(is_nothrow_copy_constructible_v<_Tp>);
- if (this != std::__addressof(__that))
-   {
- _M_value.~_Tp();
- std::construct_at(std::__addressof(_M_value), *__that);
-   }
- return *this;
-   }
-
-   // Likewise for move assignment.
-   constexpr __box&
-   operator=(__box&& __that) noexcept
-   {
- static_assert(is_nothrow_move_constructible_v<_Tp>);
- if (this != std::__addressof(__that))
-   {
- _M_value.~_Tp();
- std::construct_at(std::__addressof(_M_value), std::move(*__that));
-   }
- return *this;
-   }
-
constexpr bool
has_value() const noexcept
{ return true; };
@@ -1180,16 +1147,6 @@ namespace views::__adaptor
  return *this;
}
 
-   constexpr __non_propagating_cache&
-   operator=(_Tp __val)
-   {
- this->_M_reset();
- std::construct_at(std::__addressof(this->_M_payload._M_payload),
-   std::in_place, std::move(__val));
- this->_M_payload._M_engaged = true;
- return *this;
-   }
-
constexpr _Tp&
operator*() noexcept
{ return this->_M_get(); }
@@ -2886,7 +2843,7 @@ namespace views::__adaptor
if constexpr (forward_range<_Vp>)
  return _M_current;
else
- return *_M_parent->_M_current;
+ return _M_parent->_M_current;
  }
 
  constexpr auto&
@@ -2895,7 +2852,7 @@ namespace views::__adaptor
if constexpr (forward_range<_Vp>)
  return _M_current;
else
- return *_M_parent->_M_current;
+ return _M_parent->_M_current;
  }
 
  _Parent* _M_parent = nullptr;
@@ -3143,13 +3100,14 @@ namespace views::__adaptor
   // XXX: _M_current is "present only if !forward_range"
   [[no_unique_address]]
__detail::__maybe_present_t,
- __detail::__non_propagating_cache>> _M_current;
+

Re: [PATCH 1/3, 11 backport] libstdc++: Implement P2325 changes to default-constructibility of views

2022-02-10 Thread Patrick Palka via Gcc-patches
On Thu, 10 Feb 2022, Patrick Palka wrote:

> Tested on x86_64-pc-linux-gnu, does this look OK for the 11 branch?
> The backport to the 10 branch hasn't been started yet, I figured it'd
> be good to first get the 11 backport right then base the 10 backport
> on the 11 one.
> 
> NB: This backport of r12-1606 to the 11 branch deliberately omits parts
> of P2325R3 so as to maximize backward compatibility with pre-P2325R3 code.
> In particular, we don't remove the default ctors for back_insert_iterator,
> front_insert_iterator, ostream_iterator, ref_view and basic_istream_view.
> 
> This implements the wording changes of P2325R3 "Views should not be
> required to be default constructible".  Changes are relatively
> straightforward, besides perhaps those to __box (which now stands
> for copyable-box instead of semiregular-box) and __non_propagating_cache.
> 
> For __box, this patch implements the recommended practice to also avoid
> std::optional when the boxed type is nothrow_move/copy_constructible.
> 
> For __non_propagating_cache, now that it's used by split_view::_M_current,
> we need to add assignment from a value of the underlying type to the
> subset of the std::optional API implemented for the cache (needed by
> split_view::begin()).  Hence the new __non_propagating_cache::operator=
> overload.
> 
> In passing, this fixes the undesirable list-init in the constructors of
> the partial specialization of __box as reported in PR100475 comment #7.
> 
>   PR libstdc++/103904
> 
> libstdc++-v3/ChangeLog:
> 
>   * include/bits/iterator_concepts.h (weakly_incrementable): Remove
>   default_initializable requirement.
>   * include/bits/ranges_base.h (ranges::view): Likewise.
>   * include/bits/ranges_util.h (subrange): Constrain the default
>   ctor.
>   * include/bits/stl_iterator.h (common_iterator): Constrain the
>   default ctor.
>   (counted_iterator): Likewise.
>   * include/std/ranges (__detail::__box::operator=): Handle
>   self-assignment in the primary template.
>   (__detail::__box): In the partial specialization: adjust
>   constraints as per P2325.  Add specialized operator= for the
>   case when the wrapped type is not copyable.  Constrain the
>   default ctor.  Avoid list-initialization.
>   (single_view): Constraint the default ctor.
>   (iota_view): Relax semiregular constraint to copyable.
>   Constrain the default ctor.
>   (iota_view::_Iterator): Constraint the default ctor.
>   (basic_istream_view): Remove the default ctor.  Remove NSDMIs.
>   Remove redundant checks for empty _M_stream.
>   (basic_istream_view::_Iterator): Likewise.
>   (ref_view): Remove the default ctor.  Remove NSDMIs.
>   (ref_view::_Iterator): Constrain the default ctor.
>   (__detail::__non_propagating_cache::operator=): Define overload
>   for assigning from a value of the underlying type.
>   (filter_view): Likewise.
>   (filter_view::_Iterator): Likewise.
>   (transform_view): Likewise.
>   (transform_view::_Iterator): Likewise.
>   (take_view): Likewise.
>   (take_view::_Iterator): Likewise.
>   (take_while_view): Likewise.
>   (take_while_view::_Iterator): Likewise.
>   (drop_while_view): Likewise.
>   (drop_while_view::_Iterator): Likewise.
>   (join_view): Likewise.
>   (split_view::_OuterIter::__current): Adjust after changing the
>   type of _M_current.
>   (split_view::_M_current): Wrap it in a __non_propagating_cache.
>   (split_view::split_view): Constrain the default ctor.
>   (common_view): Constrain the default ctor.
>   (reverse_view): Likewise.
>   (elements_view): Likewise.
>   * include/std/span (enable_view>):
>   Define this partial specialization to true unconditionally.
>   * include/std/version (__cpp_lib_ranges): Adjust value.
>   * testsuite/std/ranges/adaptors/detail/semiregular_box.cc:
>   Rename to ...
>   * testsuite/std/ranges/adaptors/detail/copyable_box.cc: ... this.
>   (test02): Adjust now that __box is copyable-box not
>   semiregular-box.
>   (test03): New test.
>   * testsuite/std/ranges/p2325.cc: New test.
>   * testsuite/std/ranges/single_view.cc (test06): New test.
>   * testsuite/std/ranges/view.cc: Adjust now that view doesn't
>   require default_initializable.
> 
> (cherry picked from commit 4b4f5666b4c2f3aab2a9f3d53d394e390b9b682d)
> ---
>  libstdc++-v3/include/bits/iterator_concepts.h |   3 +-
>  libstdc++-v3/include/bits/ranges_base.h   |   3 +-
>  libstdc++-v3/include/bits/ranges_util.h   |   2 +-
>  libstdc++-v3/include/bits/stl_iterator.h  | 

Re: [PATCH 1/3, 11 backport] libstdc++: Implement P2325 changes to default-constructibility of views

2022-02-10 Thread Patrick Palka via Gcc-patches
On Thu, 10 Feb 2022, Patrick Palka wrote:

> Tested on x86_64-pc-linux-gnu, does this look OK for the 11 branch?
> The backport to the 10 branch hasn't been started yet, I figured it'd
> be good to first get the 11 backport right then base the 10 backport
> on the 11 one.
> 
> NB: This backport of r12-1606 to the 11 branch deliberately omits parts
> of P2325R3 so as to maximize backward compatibility with pre-P2325R3 code.
> In particular, we don't remove the default ctors for back_insert_iterator,
> front_insert_iterator, ostream_iterator, ref_view and basic_istream_view.

FWIW here's a diff of the changes in this backport relative to r12-1606:

 libstdc++-v3/include/bits/stl_iterator.h   | 13 ++-
 libstdc++-v3/include/bits/stream_iterator.h|  5 +
 libstdc++-v3/include/std/ranges| 24 +++--
 .../24_iterators/back_insert_iterator/constexpr.cc |  3 ++-
 .../front_insert_iterator/constexpr.cc |  3 ++-
 .../ostream_iterator/requirements/constexpr.cc | 24 +
 libstdc++-v3/testsuite/std/ranges/97600.cc |  3 ++-
 libstdc++-v3/testsuite/std/ranges/p2325.cc | 25 ++
 8 files changed, 89 insertions(+), 11 deletions(-)

diff --git a/libstdc++-v3/include/bits/stl_iterator.h 
b/libstdc++-v3/include/bits/stl_iterator.h
index 7fe727d8093..549bc26dee5 100644
--- a/libstdc++-v3/include/bits/stl_iterator.h
+++ b/libstdc++-v3/include/bits/stl_iterator.h
@@ -639,6 +639,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   typedef _Container  container_type;
 #if __cplusplus > 201703L
   using difference_type = ptrdiff_t;
+
+  constexpr back_insert_iterator() noexcept : container(nullptr) { }
 #endif
 
   /// The only way to create this %iterator is with a container.
@@ -740,6 +742,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   typedef _Container  container_type;
 #if __cplusplus > 201703L
   using difference_type = ptrdiff_t;
+
+  constexpr front_insert_iterator() noexcept : container(nullptr) { }
 #endif
 
   /// The only way to create this %iterator is with a container.
@@ -839,12 +843,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 {
 #if __cplusplus > 201703L && defined __cpp_lib_concepts
   using _Iter = std::__detail::__range_iter_t<_Container>;
+
+protected:
+  _Container* container = nullptr;
+  _Iter iter = _Iter();
 #else
   typedef typename _Container::iterator_Iter;
-#endif
+
 protected:
   _Container* container;
   _Iter iter;
+#endif
 
 public:
   /// A nested typedef for the type of whatever container you used.
@@ -852,6 +861,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
 #if __cplusplus > 201703L && defined __cpp_lib_concepts
   using difference_type = ptrdiff_t;
+
+  insert_iterator() = default;
 #endif
 
   /**
diff --git a/libstdc++-v3/include/bits/stream_iterator.h 
b/libstdc++-v3/include/bits/stream_iterator.h
index d07474d4996..fd8920b8d01 100644
--- a/libstdc++-v3/include/bits/stream_iterator.h
+++ b/libstdc++-v3/include/bits/stream_iterator.h
@@ -192,6 +192,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   const _CharT*_M_string;
 
 public:
+#if __cplusplus > 201703L
+  constexpr ostream_iterator() noexcept
+  : _M_stream(nullptr), _M_string(nullptr) { }
+#endif
+
   /// Construct from an ostream.
   ostream_iterator(ostream_type& __s)
   : _M_stream(std::__addressof(__s)), _M_string(0) {}
diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index a01b5e79f1f..bf6cfae2a6e 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -680,6 +680,8 @@ namespace views
 : public view_interface>
 {
 public:
+  basic_istream_view() = default;
+
   constexpr explicit
   basic_istream_view(basic_istream<_CharT, _Traits>& __stream)
: _M_stream(std::__addressof(__stream))
@@ -688,7 +690,8 @@ namespace views
   constexpr auto
   begin()
   {
-   *_M_stream >> _M_object;
+   if (_M_stream != nullptr)
+ *_M_stream >> _M_object;
return _Iterator{this};
   }
 
@@ -697,8 +700,8 @@ namespace views
   { return default_sentinel; }
 
 private:
-  basic_istream<_CharT, _Traits>* _M_stream;
-  _Val _M_object;
+  basic_istream<_CharT, _Traits>* _M_stream = nullptr;
+  _Val _M_object = _Val();
 
   struct _Iterator
   {
@@ -720,6 +723,7 @@ namespace views
_Iterator&
operator++()
{
+ __glibcxx_assert(_M_parent->_M_stream != nullptr);
  *_M_parent->_M_stream >> _M_parent->_M_object;
  return *this;
}
@@ -730,18 +734,21 @@ namespace views
 
_Val&
operator*() const
-   { return _M_parent->_M_object; }
+   {
+ __glibcxx_asser

[PATCH 1/3, 11 backport] libstdc++: Implement P2325 changes to default-constructibility of views

2022-02-10 Thread Patrick Palka via Gcc-patches
Tested on x86_64-pc-linux-gnu, does this look OK for the 11 branch?
The backport to the 10 branch hasn't been started yet, I figured it'd
be good to first get the 11 backport right then base the 10 backport
on the 11 one.

NB: This backport of r12-1606 to the 11 branch deliberately omits parts
of P2325R3 so as to maximize backward compatibility with pre-P2325R3 code.
In particular, we don't remove the default ctors for back_insert_iterator,
front_insert_iterator, ostream_iterator, ref_view and basic_istream_view.

This implements the wording changes of P2325R3 "Views should not be
required to be default constructible".  Changes are relatively
straightforward, besides perhaps those to __box (which now stands
for copyable-box instead of semiregular-box) and __non_propagating_cache.

For __box, this patch implements the recommended practice to also avoid
std::optional when the boxed type is nothrow_move/copy_constructible.

For __non_propagating_cache, now that it's used by split_view::_M_current,
we need to add assignment from a value of the underlying type to the
subset of the std::optional API implemented for the cache (needed by
split_view::begin()).  Hence the new __non_propagating_cache::operator=
overload.

In passing, this fixes the undesirable list-init in the constructors of
the partial specialization of __box as reported in PR100475 comment #7.

PR libstdc++/103904

libstdc++-v3/ChangeLog:

* include/bits/iterator_concepts.h (weakly_incrementable): Remove
default_initializable requirement.
* include/bits/ranges_base.h (ranges::view): Likewise.
* include/bits/ranges_util.h (subrange): Constrain the default
ctor.
* include/bits/stl_iterator.h (common_iterator): Constrain the
default ctor.
(counted_iterator): Likewise.
* include/std/ranges (__detail::__box::operator=): Handle
self-assignment in the primary template.
(__detail::__box): In the partial specialization: adjust
constraints as per P2325.  Add specialized operator= for the
case when the wrapped type is not copyable.  Constrain the
default ctor.  Avoid list-initialization.
(single_view): Constraint the default ctor.
(iota_view): Relax semiregular constraint to copyable.
Constrain the default ctor.
(iota_view::_Iterator): Constraint the default ctor.
(basic_istream_view): Remove the default ctor.  Remove NSDMIs.
Remove redundant checks for empty _M_stream.
(basic_istream_view::_Iterator): Likewise.
(ref_view): Remove the default ctor.  Remove NSDMIs.
(ref_view::_Iterator): Constrain the default ctor.
(__detail::__non_propagating_cache::operator=): Define overload
for assigning from a value of the underlying type.
(filter_view): Likewise.
(filter_view::_Iterator): Likewise.
(transform_view): Likewise.
(transform_view::_Iterator): Likewise.
(take_view): Likewise.
(take_view::_Iterator): Likewise.
(take_while_view): Likewise.
(take_while_view::_Iterator): Likewise.
(drop_while_view): Likewise.
(drop_while_view::_Iterator): Likewise.
(join_view): Likewise.
(split_view::_OuterIter::__current): Adjust after changing the
type of _M_current.
(split_view::_M_current): Wrap it in a __non_propagating_cache.
(split_view::split_view): Constrain the default ctor.
(common_view): Constrain the default ctor.
(reverse_view): Likewise.
(elements_view): Likewise.
* include/std/span (enable_view>):
Define this partial specialization to true unconditionally.
* include/std/version (__cpp_lib_ranges): Adjust value.
* testsuite/std/ranges/adaptors/detail/semiregular_box.cc:
Rename to ...
* testsuite/std/ranges/adaptors/detail/copyable_box.cc: ... this.
(test02): Adjust now that __box is copyable-box not
semiregular-box.
(test03): New test.
* testsuite/std/ranges/p2325.cc: New test.
* testsuite/std/ranges/single_view.cc (test06): New test.
* testsuite/std/ranges/view.cc: Adjust now that view doesn't
require default_initializable.

(cherry picked from commit 4b4f5666b4c2f3aab2a9f3d53d394e390b9b682d)
---
 libstdc++-v3/include/bits/iterator_concepts.h |   3 +-
 libstdc++-v3/include/bits/ranges_base.h   |   3 +-
 libstdc++-v3/include/bits/ranges_util.h   |   2 +-
 libstdc++-v3/include/bits/stl_iterator.h  |   3 +-
 libstdc++-v3/include/std/ranges   | 136 +
 libstdc++-v3/include/std/span |   3 +-
 libstdc++-v3/include/std/version  |   2 +-
 .../{semiregular_box.cc => copyable_box.cc}   |  51 -
 libstdc++-v3/testsuite/std/ranges/p2325.cc| 180 ++
 .../testsuite/std/ranges/single_view.cc   |  15 ++
 

<    5   6   7   8   9   10   11   12   13   14   >