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

2023-06-01 Thread Patrick Palka via Gcc-patches
For a complex alias template-id, dependent_alias_template_spec_p returns
true if any template argument of the template-id is dependent.  This
predicate indicates that substitution into the template-id may behave
differently with respect to SFINAE than substitution into the expanded
alias, and so the alias is in a way non-transparent.  For example
'first_t' in

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

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

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

This patch refines the predicate appropriately.  We need to be able to
efficiently determine which template parameters of a complex alias
template are unused, so to that end we add a new out parameter to
complex_alias_template_p and cache its result in an on-the-side
hash_map that replaces the existing TEMPLATE_DECL_COMPLEX_ALIAS_P
flag.  And in doing so, we fix a latent bug that this flag wasn't
being propagated during partial instantiation, and so we were treating
all partially instantiated member alias templates as non-complex.

PR c++/90679

gcc/cp/ChangeLog:

* cp-tree.h (TEMPLATE_DECL_COMPLEX_ALIAS_P): Remove.
(most_general_template): Constify parameter.
* pt.cc (push_template_decl): Adjust after removing
TEMPLATE_DECL_COMPLEX_ALIAS_P.
(complex_alias_tmpl_info): New hash_map.
(uses_all_template_parms_data::seen): Change type to
tree* from bool*.
(complex_alias_template_r): Adjust accordingly.
(complex_alias_template_p): Add 'seen_out' out parameter.
Call most_general_template and check PRIMARY_TEMPLATE_P.
Use complex_alias_tmpl_info to cache the result and set
'*seen_out' accordigly.
(dependent_alias_template_spec_p): Add !processing_template_decl
early exit test.  Consider dependence of only template arguments
corresponding to seen template parameters as per

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/alias-decl-75.C: New test.
---
 gcc/cp/cp-tree.h   |   7 +-
 gcc/cp/pt.cc   | 101 +++--
 gcc/testsuite/g++.dg/cpp0x/alias-decl-75.C |  24 +
 3 files changed, 100 insertions(+), 32 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-75.C

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index a1b882f11fe..5330d1e1f62 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -543,7 +543,6 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
2: DECL_THIS_EXTERN (in VAR_DECL, FUNCTION_DECL or PARM_DECL)
   DECL_IMPLICIT_TYPEDEF_P (in a TYPE_DECL)
   DECL_CONSTRAINT_VAR_P (in a PARM_DECL)
-  TEMPLATE_DECL_COMPLEX_ALIAS_P (in TEMPLATE_DECL)
   DECL_INSTANTIATING_NSDMI_P (in a FIELD_DECL)
   USING_DECL_UNRELATED_P (in USING_DECL)
3: DECL_IN_AGGR_P.
@@ -3655,10 +3654,6 @@ struct GTY(()) lang_decl {
 #define TYPE_DECL_ALIAS_P(NODE) \
   DECL_LANG_FLAG_6 (TYPE_DECL_CHECK (NODE))
 
-/* Nonzero for TEMPLATE_DECL means that it is a 'complex' alias template.  */
-#define TEMPLATE_DECL_COMPLEX_ALIAS_P(NODE) \
-  DECL_LANG_FLAG_2 (TEMPLATE_DECL_CHECK (NODE))
-
 /* Nonzero for a type which is an alias for another type; i.e, a type
which declaration was written 'using name-of-type =
another-type'.  */
@@ -7403,7 +7398,7 @@ extern tree tsubst_argument_pack  (tree, tree, 
tsubst_flags_t, tree);
 extern tree tsubst_template_args   (tree, tree, tsubst_flags_t, 
tree);
 extern tree tsubst_template_arg(tree, tree, 
tsubst_flags_t, tree);
 extern tree tsubst_function_parms  (tree, tree, tsubst_flags_t, 
tree);
-extern tree most_general_template  (tree);
+extern tree most_general_template  (const_tree);
 extern tree get_mostly_instantiated_function_type (tree);
 extern bool problematic_instantiation_changed  (void);
 extern void record_last_problematic_instantiation (void);
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 7fb3e75bceb..1b28195e10d 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -211,7 +211,6 @@ static tree listify (tree);
 static tree listify_autos (tree, tree);
 static tree tsubst_template_parm (tree, tree, tsubst_flags_t);
 static tree instantiate_alias_template (tree, tree, tsubst_flags_t);
-static bool complex_alias_template_p (const_tree tmpl);
 static tree get_underlying_template (tree);
 static tree tsubst_attributes (tree, tree, tsubst_flags_t, tree);
 static tree canonicalize_expr_argument (tree, tsubst_flags_t);
@@ -6233,8 +6232,6 @@ push_template_decl (tree decl, bool is_friend)
   

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

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

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

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

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

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

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

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

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

PR c++/90679

gcc/cp/ChangeLog:

* cp-tree.h (comp_template_args): Remove partial_order
parameter.
(template_args_equal): Likewise.
* pt.cc (iterative_hash_template_arg) : Hash
the template and arguments for specializations that use
structural equality.
(comparing_for_partial_ordering): New flag.
(template_args_equal): Remove partial order parameter and
use comparing_for_partial_ordering instead.
(comp_template_args): Likewise.
(comp_template_args_porder): Set comparing_for_partial_ordering
instead.  Make static.
(any_template_arguments_need_structural_equality_p): Return true
for an argument that's a dependent alias template specialization
or a class template specialization that itself needs structural
equality.
* tree.cc (cp_tree_equal) : Adjust call to
comp_template_args.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/alias-decl-75a.C: New test.
* g++.dg/cpp0x/alias-decl-75b.C: New test.
---
 gcc/cp/cp-tree.h|  4 +--
 gcc/cp/pt.cc| 40 +
 gcc/cp/tree.cc  |  2 +-
 gcc/testsuite/g++.dg/cpp0x/alias-decl-75a.C | 26 ++
 gcc/testsuite/g++.dg/cpp0x/alias-decl-75b.C | 26 ++
 5 files changed, 88 insertions(+), 10 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-75a.C
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-75b.C

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 5330d1e1f62..f08e5630a5c 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7381,8 +7381,8 @@ extern int template_class_depth   (tree);
 extern int is_specialization_of(tree, tree);
 extern bool is_specialization_of_friend(tree, tree);
 extern bool comp_template_args (tree, tree, tree * = NULL,
-tree * = NULL, bool = false);
-extern int template_args_equal  (tree, tree, bool = false);
+tree * = NULL);
+extern int template_args_equal  (tree, tree);
 extern tree maybe_process_partial_specialization (tree);
 extern tree most_specialized_instantiation (tree);
 extern tree most_specialized_partial_spec   (tree, tsubst_flags_t);
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 1b28195e10d..1a32f10b22b 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -1913,6 +1913,11 @@ iterative_hash_template_arg (tree arg, hashval_t val)
default:
  if (tree canonical = TYPE_CANONICAL (arg))
val = iterative_hash_object (TYPE_HASH (canonical), val);
+ else if (tree ti = TYPE_TEMPLATE_INFO (arg))
+   {
+ val = iterative_hash_template_arg (TI_TEMPLATE (ti), val);
+ val = iterative_hash_template_arg (TI_ARGS (ti), val);
+   }
  break;
}
 
@@ -9296,6 +9301,12 @@ coerce_template_parms (tree parms,
   return return_full_args ? new_args : new_inner_args;
 }
 
+/* Whether we are comparing template arguments during partial ordering
+   (and therefore want the comparison to look through dependent alias
+   template specializations).  */
+
+static int comparing_for_partial_ordering;
+
 /* Returns true if T is a wrapper to make a C++20 template paramet

Re: [PATCH 04/14] c++: use _P() defines from tree.h

2023-06-01 Thread Patrick Palka via Gcc-patches
On Sat, May 13, 2023 at 7:26 PM Bernhard Reutner-Fischer via
Gcc-patches  wrote:
>
> From: Bernhard Reutner-Fischer 
>
> gcc/cp/ChangeLog:
>
> * call.cc (promoted_arithmetic_type_p): Use _P defines from tree.h.
> (build_conditional_expr): Ditto.
> (convert_like_internal): Ditto.
> (convert_arg_to_ellipsis): Ditto.
> (build_over_call): Ditto.
> (compare_ics): Ditto.
> * class.cc (is_empty_base_ref): Ditto.
> * coroutines.cc (rewrite_param_uses): Ditto.
> * cp-tree.h (DECL_DISCRIMINATOR_P): Ditto.
> (ARITHMETIC_TYPE_P): Ditto.
> * cvt.cc (ocp_convert): Ditto.
> * cxx-pretty-print.cc (pp_cxx_template_argument_list): Ditto.
> * decl.cc (layout_var_decl): Ditto.
> (get_tuple_size): Ditto.
> * error.cc (dump_simple_decl): Ditto.
> * lambda.cc (start_lambda_scope): Ditto.
> * mangle.cc (write_template_arg): Ditto.
> * method.cc (spaceship_comp_cat): Ditto.
> * module.cc (node_template_info): Ditto.
> (trees_out::start): Ditto.
> (trees_out::decl_node): Ditto.
> (trees_in::read_var_def): Ditto.
> (set_instantiating_module): Ditto.
> * name-lookup.cc (maybe_record_mergeable_decl): Ditto.
> (consider_decl): Ditto.
> (maybe_add_fuzzy_decl): Ditto.
> * pt.cc (convert_nontype_argument): Ditto.
> * semantics.cc (handle_omp_array_sections_1): Ditto.
> (finish_omp_clauses): Ditto.
> (finish_omp_target_clauses_r): Ditto.
> (is_this_parameter): Ditto.
> * tree.cc (build_cplus_array_type): Ditto.
> (is_this_expression): Ditto.
> * typeck.cc (do_warn_enum_conversions): Ditto.
> * typeck2.cc (store_init_value): Ditto.
> (check_narrowing): Ditto.
> ---
>  gcc/cp/call.cc | 42 +++---
>  gcc/cp/class.cc|  2 +-
>  gcc/cp/coroutines.cc   |  2 +-
>  gcc/cp/cp-tree.h   |  4 ++--
>  gcc/cp/cvt.cc  |  2 +-
>  gcc/cp/cxx-pretty-print.cc |  2 +-
>  gcc/cp/decl.cc |  4 ++--
>  gcc/cp/error.cc|  2 +-
>  gcc/cp/lambda.cc   |  2 +-
>  gcc/cp/mangle.cc   |  2 +-
>  gcc/cp/method.cc   |  2 +-
>  gcc/cp/module.cc   | 12 +--
>  gcc/cp/name-lookup.cc  |  6 +++---
>  gcc/cp/pt.cc   |  2 +-
>  gcc/cp/semantics.cc| 24 +++---
>  gcc/cp/tree.cc |  4 ++--
>  gcc/cp/typeck.cc   |  4 ++--
>  gcc/cp/typeck2.cc  | 10 -
>  18 files changed, 64 insertions(+), 64 deletions(-)
>
> diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
> index 2a06520c0c1..6e13d17f6b8 100644
> --- a/gcc/cp/call.cc
> +++ b/gcc/cp/call.cc
> @@ -2746,7 +2746,7 @@ promoted_arithmetic_type_p (tree type)
>   integral types plus floating types.  */
>return ((CP_INTEGRAL_TYPE_P (type)
>&& same_type_p (type_promotes_to (type), type))
> - || TREE_CODE (type) == REAL_TYPE);
> + || SCALAR_FLOAT_TYPE_P (type));
>  }
>
>  /* Create any builtin operator overload candidates for the operator in
> @@ -5759,10 +5759,10 @@ build_conditional_expr (const op_location_t &loc,
>if ((TREE_CODE (arg2) == EXCESS_PRECISION_EXPR
> || TREE_CODE (arg3) == EXCESS_PRECISION_EXPR)
>&& (TREE_CODE (arg2_type) == INTEGER_TYPE
> - || TREE_CODE (arg2_type) == REAL_TYPE
> + || SCALAR_FLOAT_TYPE_P (arg2_type)
>   || TREE_CODE (arg2_type) == COMPLEX_TYPE)
>&& (TREE_CODE (arg3_type) == INTEGER_TYPE
> - || TREE_CODE (arg3_type) == REAL_TYPE
> + || SCALAR_FLOAT_TYPE_P (arg3_type)
>   || TREE_CODE (arg3_type) == COMPLEX_TYPE))
>  {
>semantic_result_type
> @@ -5775,8 +5775,8 @@ build_conditional_expr (const op_location_t &loc,
> t1 = TREE_TYPE (t1);
>   if (TREE_CODE (t2) == COMPLEX_TYPE)
> t2 = TREE_TYPE (t2);
> - gcc_checking_assert (TREE_CODE (t1) == REAL_TYPE
> -  && TREE_CODE (t2) == REAL_TYPE
> + gcc_checking_assert (SCALAR_FLOAT_TYPE_P (t1)
> +  && SCALAR_FLOAT_TYPE_P (t2)
>&& (extended_float_type_p (t1)
>|| extended_float_type_p (t2))
>&& cp_compare_floating_point_conversion_ranks
> @@ -6127,8 +6127,8 @@ build_conditional_expr (const op_location_t &loc,
> t1 = TREE_TYPE (t1);
>   if (TREE_CODE (t2) == COMPLEX_TYPE)
> t2 = TREE_TYPE (t2);
> - gcc_checking_assert (TREE_CODE (t1) == REAL_TYPE
> -  && TREE_CODE (t2) == REAL_TYPE
> + gcc_checking_assert (SCALAR_FLOAT_TYPE_P (t1)
> +  && SCALAR_FLOAT_TYPE_P (t2)
>&& (extended_float_type_p (t1)
>

Re: [PATCH] c++: ahead of time variable template-id coercion [PR89442]

2023-06-01 Thread Patrick Palka via Gcc-patches
On Wed, May 3, 2023 at 9:50 AM Patrick Palka  wrote:
>
> This patch makes us coerce the arguments of a variable template-id ahead
> of time, as we do for other template-ids, which allows us to immediately
> diagnose template parameter/argument kind mismatches and arity mismatches.
>
> Unfortunately this causes a regression in cpp1z/constexpr-if20.C: coercing
> the variable template-id m ahead of time means we strip it of
> typedefs, yielding m::q, typename C::q>, but in this
> stripped form we're directly using 'i' and so we expect to have captured
> it.  This is PR107437 but with a variable template instead of a class
> template.  I'm not sure how to fix this :(
>
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk?

Ping.

>
> PR c++/89442
> PR c++/107437
>
> gcc/cp/ChangeLog:
>
> * cp-tree.h (lookup_template_variable): Add complain parameter.
> * parser.cc (cp_parser_template_id): Pass tf_warning_or_error
> to lookup_template_variable.
> * pt.cc (lookup_template_variable): Add complain parameter.
> Coerce template arguments here ...
> (finish_template_variable): ... instead of here.
> (lookup_and_finish_template_variable): Check for error_mark_node
> result from lookup_template_variable.
> (tsubst_copy) : Pass complain to
> lookup_template_variable.
> (instantiate_template): Use build2 instead of
> lookup_template_variable to build a TEMPLATE_ID_EXPR
> for most_specialized_partial_spec.
>
> gcc/testsuite/ChangeLog:
>
> * g++.dg/cpp/pr64127.C: Expect "expected unqualified-id at end
> of input" error.
> * g++.dg/cpp0x/alias-decl-ttp1.C: Fix template parameter/argument
> kind mismatch for variable template has_P_match_V.
> * g++.dg/cpp1y/pr72759.C: Expect "template argument 1 is invalid"
> error.
> * g++.dg/cpp1z/constexpr-if20.C: XFAIL test due to bogus "'i' is
> not captured" error.
> * g++.dg/cpp1z/noexcept-type21.C: Fix arity of variable template d.
> * g++.dg/diagnostic/not-a-function-template-1.C: Add default
> template argument to variable template A so that A<> is valid.
> * g++.dg/parse/error56.C: Don't expect "ISO C++ forbids
> declaration with no type" error.
> * g++.dg/parse/template30.C: Don't expect "parse error in
> template argument list" error.
> * g++.dg/cpp1y/var-templ80.C: New test.
> ---
>  gcc/cp/cp-tree.h  |  2 +-
>  gcc/cp/parser.cc  |  2 +-
>  gcc/cp/pt.cc  | 20 ++-
>  gcc/testsuite/g++.dg/cpp/pr64127.C|  2 +-
>  gcc/testsuite/g++.dg/cpp0x/alias-decl-ttp1.C  |  2 +-
>  gcc/testsuite/g++.dg/cpp1y/pr72759.C  |  2 +-
>  gcc/testsuite/g++.dg/cpp1y/var-templ80.C  | 12 +++
>  gcc/testsuite/g++.dg/cpp1z/constexpr-if20.C   |  1 +
>  gcc/testsuite/g++.dg/cpp1z/noexcept-type21.C  |  2 +-
>  .../diagnostic/not-a-function-template-1.C|  2 +-
>  gcc/testsuite/g++.dg/parse/error56.C  |  1 -
>  gcc/testsuite/g++.dg/parse/template30.C   |  3 +--
>  12 files changed, 32 insertions(+), 19 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp1y/var-templ80.C
>
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index c9c4cd6f32f..96807282ec5 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -7349,7 +7349,7 @@ extern bool redeclare_class_template  
> (tree, tree, tree);
>  extern tree lookup_template_class  (tree, tree, tree, tree,
>  int, tsubst_flags_t);
>  extern tree lookup_template_function   (tree, tree);
> -extern tree lookup_template_variable   (tree, tree);
> +extern tree lookup_template_variable   (tree, tree, tsubst_flags_t);
>  extern bool uses_template_parms(tree);
>  extern bool uses_template_parms_level  (tree, int);
>  extern bool uses_outer_template_parms_in_constraints (tree);
> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> index d89553e7da8..4982583809b 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -18525,7 +18525,7 @@ cp_parser_template_id (cp_parser *parser,
>  }
>else if (variable_template_p (templ))
>  {
> -  template_id = lookup_template_variable (templ, arguments);
> +  template_id = lookup_template_variable (templ, arguments, 
> tf_warning_or_error);
>if (TREE_CODE (template_id) == TEMPLATE_ID_EXPR)
> SET_EXPR_LOCATION (template_id, combined_loc);
>  }
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 930291917f2..abf99feab20 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -10329,11 +10329,16 @@ lookup_template_class (tree d1, tree arglist, tree 
> in_decl, tree context,
>  /* Return a TEMPLATE_ID_EXPR for the given variable template and ARGL

[PATCH] c++: fix up caching of level lowered ttps

2023-06-01 Thread Patrick Palka via Gcc-patches
Due to level/depth mismatches between the template parameters of a level
lowered ttp and the original ttp, the ttp comparison check added by
r14-418-g0bc2a1dc327af9 never actually holds outside of erroneous cases.
Moreover, it'd be good to cache the overall TEMPLATE_TEMPLATE_PARM
instead of just the corresponding TEMPLATE_PARM_INDEX.

It's tricky to cache all level lowered ttps since the result of level
lowering may depend on more than just the depth of the arguments, e.g.
for TT in

  template
  struct A
  {
template class TT>
void f();
  }

the substitution T=int yields a different level-lowerd ttp than T=char.
But these kinds of ttps seem to be rare in practice, and "simple" ttps
that don't depend on outer template parameters are easy enough to
cache like so.  Unfortunately, this means we're back to expecting a
duplicate error in nontype12.C again since the ttp in question is
not "simple" so caching of the (erroneous) lowered ttp doesn't happen.

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?  This reduces memory usage of range-v3's zip.cpp by 1%.

gcc/cp/ChangeLog:

* cp-tree.h (TEMPLATE_PARM_DESCENDANTS): Harden.
(TEMPLATE_TYPE_DESCENDANTS): Define.
(TEMPLATE_TEMPLATE_PARM_SIMPLE_P): Define.
* pt.cc (reduce_template_parm_level): Revert
r14-418-g0bc2a1dc327af9 change.
(process_template_parm): Set TEMPLATE_TEMPLATE_PARM_SIMPLE_P
appropriately.
(uses_outer_template_parms): Determine the outer depth of
a template template parm without relying on DECL_CONTEXT.
(tsubst) : Cache lowering a
simple template template parm.  Consistently use 'code'.

gcc/testsuite/ChangeLog:

* g++.dg/template/nontype12.C: Expect a duplicate error again.
---
 gcc/cp/cp-tree.h  | 10 +-
 gcc/cp/pt.cc  | 37 +--
 gcc/testsuite/g++.dg/template/nontype12.C |  3 +-
 3 files changed, 31 insertions(+), 19 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index f08e5630a5c..cd762667bec 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -525,6 +525,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
5: CLASS_TYPE_P (in RECORD_TYPE and UNION_TYPE)
   ENUM_FIXED_UNDERLYING_TYPE_P (in ENUMERAL_TYPE)
   AUTO_IS_DECLTYPE (in TEMPLATE_TYPE_PARM)
+  TEMPLATE_TEMPLATE_PARM_SIMPLE_P (in TEMPLATE_TEMPLATE_PARM)
6: TYPE_DEPENDENT_P_VALID
 
Usage of DECL_LANG_FLAG_?:
@@ -5991,7 +5992,7 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, 
TYPENAME_FLAG };
((template_parm_index*)TEMPLATE_PARM_INDEX_CHECK (NODE))
 #define TEMPLATE_PARM_IDX(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->index)
 #define TEMPLATE_PARM_LEVEL(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->level)
-#define TEMPLATE_PARM_DESCENDANTS(NODE) (TREE_CHAIN (NODE))
+#define TEMPLATE_PARM_DESCENDANTS(NODE) (TREE_CHAIN (TEMPLATE_PARM_INDEX_CHECK 
(NODE)))
 #define TEMPLATE_PARM_ORIG_LEVEL(NODE) (TEMPLATE_PARM_INDEX_CAST 
(NODE)->orig_level)
 #define TEMPLATE_PARM_DECL(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->decl)
 #define TEMPLATE_PARM_PARAMETER_PACK(NODE) \
@@ -6009,6 +6010,8 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, 
TYPENAME_FLAG };
   (TEMPLATE_PARM_LEVEL (TEMPLATE_TYPE_PARM_INDEX (NODE)))
 #define TEMPLATE_TYPE_ORIG_LEVEL(NODE) \
   (TEMPLATE_PARM_ORIG_LEVEL (TEMPLATE_TYPE_PARM_INDEX (NODE)))
+#define TEMPLATE_TYPE_DESCENDANTS(NODE) \
+  (TEMPLATE_PARM_DESCENDANTS (TEMPLATE_TYPE_PARM_INDEX (NODE)))
 #define TEMPLATE_TYPE_DECL(NODE) \
   (TEMPLATE_PARM_DECL (TEMPLATE_TYPE_PARM_INDEX (NODE)))
 #define TEMPLATE_TYPE_PARAMETER_PACK(NODE) \
@@ -6018,6 +6021,11 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, 
TYPENAME_FLAG };
 #define CLASS_PLACEHOLDER_TEMPLATE(NODE) \
   (DECL_INITIAL (TYPE_NAME (TEMPLATE_TYPE_PARM_CHECK (NODE
 
+/* True iff the template parameters of this TEMPLATE_TEMPLATE_PARM don't
+   depend on outer template parameters.  */
+#define TEMPLATE_TEMPLATE_PARM_SIMPLE_P(NODE) \
+  (TYPE_LANG_FLAG_5 (TEMPLATE_TEMPLATE_PARM_CHECK (NODE)))
+
 /* Contexts in which auto deduction occurs. These flags are
used to control diagnostics in do_auto_deduction.  */
 
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 1a32f10b22b..15128cf3c7c 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -219,6 +219,7 @@ static tree enclosing_instantiation_of (tree tctx);
 static void instantiate_body (tree pattern, tree args, tree d, bool nested);
 static tree maybe_dependent_member_ref (tree, tree, tsubst_flags_t, tree);
 static void mark_template_arguments_used (tree, tree);
+static bool uses_outer_template_parms (tree);
 
 /* Make the current scope suitable for access checking when we are
processing T.  T can be FUNCTION_DECL for instantiated function
@@ -4554,12 +4555,7 @@ reduce_template_parm_level (tree index, tree type, int 
levels, tree args,
   if (TEMPLATE_PARM_DESCENDANTS (index) == NULL_TREE
   || (TEMPLATE_PARM_LEVEL 

[PATCH] c++: is_specialization_of_friend confusion [PR109923]

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

-- >8 --

The check for a non-template member function of a class template in
is_specialization_of_friend is overbroad, and accidentally holds for a
non-template hidden friend too, which causes the predicate to return
true for

  decl = void non_templ_friend(A, A)
  friend_decl = void non_templ_friend(A, A)

This patch refines the check appropriately.

PR c++/109923

gcc/cp/ChangeLog:

* pt.cc (is_specialization_of_friend): Fix overbroad check for
a non-template member function of a class template.

gcc/testsuite/ChangeLog:

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

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 7c2a5647665..a15d1d062c6 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -1319,6 +1319,7 @@ is_specialization_of_friend (tree decl, tree friend_decl)
  of a template class, we want to check if DECL is a specialization
  if this.  */
   if (TREE_CODE (friend_decl) == FUNCTION_DECL
+  && DECL_CLASS_SCOPE_P (friend_decl)
   && DECL_TEMPLATE_INFO (friend_decl)
   && !DECL_USE_TEMPLATE (friend_decl))
 {
diff --git a/gcc/testsuite/g++.dg/template/friend79.C 
b/gcc/testsuite/g++.dg/template/friend79.C
new file mode 100644
index 000..cd2030df019
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/friend79.C
@@ -0,0 +1,20 @@
+// PR c++/109923
+
+template
+struct A {
+private:
+  int x;
+
+public:
+  A() : x(0) { }
+
+  friend void non_templ_friend(A val, A weird) {
+val.x++;   // always works
+weird.x++; // { dg-error "private" } should only work when T=void
+  }
+};
+
+int main() {
+  non_templ_friend(A(), A()); // { dg-bogus "" }
+  non_templ_friend(A(), A());  // { dg-message "required from here" 
}
+}
-- 
2.41.0.rc1.10.g9e49351c30



[PATCH] c++: simplify TEMPLATE_TEMPLATE_PARM hashing

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

-- >8 --

r10-7815-gaa576f2a860c82 added special hashing for TEMPLATE_TEMPLATE_PARM
since non-lowered ttps had TYPE_CANONICAL but level lowered ttps did not.
But this is no longer the case ever since r13-737-gd0ef9e06197d14 made
us set TYPE_CANONICAL for level lowered ttps as well.  So this special
hashing is now unnecessary, and we can fall back to using TYPE_CANONICAL.

gcc/cp/ChangeLog:

* pt.cc (iterative_hash_template_arg): Don't hash
TEMPLATE_TEMPLATE_PARM specially.
---
 gcc/cp/pt.cc | 13 +
 1 file changed, 1 insertion(+), 12 deletions(-)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 688a87a4bd3..7c2a5647665 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -1879,19 +1879,8 @@ iterative_hash_template_arg (tree arg, hashval_t val)
  return hash_tmpl_and_args (TI_TEMPLATE (ti), TI_ARGS (ti));
}
 
-  switch (TREE_CODE (arg))
+  switch (code)
{
-   case TEMPLATE_TEMPLATE_PARM:
- {
-   tree tpi = TEMPLATE_TYPE_PARM_INDEX (arg);
-
-   /* Do not recurse with TPI directly, as that is unbounded
-  recursion.  */
-   val = iterative_hash_object (TEMPLATE_PARM_LEVEL (tpi), val);
-   val = iterative_hash_object (TEMPLATE_PARM_IDX (tpi), val);
- }
- break;
-
case  DECLTYPE_TYPE:
  val = iterative_hash_template_arg (DECLTYPE_TYPE_EXPR (arg), val);
  break;
-- 
2.41.0.rc1.10.g9e49351c30



[PATCH] c++: replace in_template_function

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

-- >8 --

All uses of in_template_function besides the one in cp_make_fname_decl
seem like they could be generalized to apply to all template contexts,
not just function templates.  To that end this patch replaces the
predicate with a cheaper and more general in_template_context predicate
that returns true for all template contexts.  If we legitimately need
to consider only function template contexts, as in cp_make_fname_decl,
we can just additionallly check e.g. current_function_decl.

One concrete benefit of this is that we no longer instantiate/odr-use
entities based on uses within a non-function template such as in the
adjusted testcase below.

gcc/cp/ChangeLog:

* class.cc (build_base_path): Check in_template_context instead
of in_template_function.
(resolves_to_fixed_type_p): Likewise.
* cp-tree.h (in_template_context): Define.
(in_template_function): Remove.
* decl.cc (cp_make_fname_decl): Check current_function_decl
and in_template_context instead of in_template_function.
* decl2.cc (mark_used): Check in_template_context instead of
in_template_function.
* pt.cc (in_template_function): Remove.
* semantics.cc (enforce_access): Check in_template_context
instead of current_template_parms directly.

gcc/testsuite/ChangeLog:

* g++.dg/warn/Waddress-of-packed-member2.C: No longer expect a()
to be marked as odr-used.
---
 gcc/cp/class.cc   |  4 ++--
 gcc/cp/cp-tree.h  |  2 +-
 gcc/cp/decl.cc|  2 +-
 gcc/cp/decl2.cc   |  2 +-
 gcc/cp/pt.cc  | 19 ---
 gcc/cp/semantics.cc   |  2 +-
 .../g++.dg/warn/Waddress-of-packed-member2.C  |  2 +-
 7 files changed, 7 insertions(+), 26 deletions(-)

diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc
index bc84f4f731a..778759237dc 100644
--- a/gcc/cp/class.cc
+++ b/gcc/cp/class.cc
@@ -344,7 +344,7 @@ build_base_path (enum tree_code code,
 
   bool uneval = (cp_unevaluated_operand != 0
 || processing_template_decl
-|| in_template_function ());
+|| in_template_context);
 
   /* For a non-pointer simple base reference, express it as a COMPONENT_REF
  without taking its address (and so causing lambda capture, 91933).  */
@@ -8055,7 +8055,7 @@ resolves_to_fixed_type_p (tree instance, int* nonnull)
   /* processing_template_decl can be false in a template if we're in
  instantiate_non_dependent_expr, but we still want to suppress
  this check.  */
-  if (in_template_function ())
+  if (in_template_context)
 {
   /* In a template we only care about the type of the result.  */
   if (nonnull)
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index a1b882f11fe..ce2095c7aaa 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1924,6 +1924,7 @@ extern GTY(()) struct saved_scope *scope_chain;
 #define current_template_parms scope_chain->template_parms
 #define current_template_depth \
   (current_template_parms ? TMPL_PARMS_DEPTH (current_template_parms) : 0)
+#define in_template_context (current_template_parms != NULL_TREE)
 
 #define processing_template_decl scope_chain->x_processing_template_decl
 #define processing_specialization scope_chain->x_processing_specialization
@@ -7353,7 +7354,6 @@ extern tree lookup_template_variable  (tree, 
tree);
 extern bool uses_template_parms(tree);
 extern bool uses_template_parms_level  (tree, int);
 extern bool uses_outer_template_parms_in_constraints (tree);
-extern bool in_template_function   (void);
 extern bool need_generic_capture   (void);
 extern tree instantiate_class_template (tree);
 extern tree instantiate_template   (tree, tree, tsubst_flags_t);
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index a672e4844f1..3985c6d2d1f 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -5021,7 +5021,7 @@ cp_make_fname_decl (location_t loc, tree id, int type_dep)
   tree domain = NULL_TREE;
   tree init = NULL_TREE;
 
-  if (!(type_dep && in_template_function ()))
+  if (!(type_dep && current_function_decl && in_template_context))
 {
   const char *name = NULL;
   bool release_name = false;
diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc
index b510cdac554..b402befba6d 100644
--- a/gcc/cp/decl2.cc
+++ b/gcc/cp/decl2.cc
@@ -5782,7 +5782,7 @@ mark_used (tree decl, tsubst_flags_t complain /* = 
tf_warning_or_error */)
  && DECL_OMP_DECLARE_REDUCTION_P (decl)))
 maybe_instantiate_decl (decl);
 
-  if (processing_template_decl || in_template_function ())
+  if (processing_template_decl || in_template_context)
 return true;
 
   /* Check this too in case we're within instantiate_non_dependent_expr. 

[PATCH] c++: bad 'this' conversion for nullary memfn [PR106760]

2023-06-02 Thread Patrick Palka via Gcc-patches
Bootstrapped and regtested on x86_64-pc-linu-xgnu, does this look OK for trunk?

-- >8 --

Here we notice the 'this' conversion for the call f() is bad, so
we correctly defer instantiating it, but we end up never adding it to
'bad_fns' since missing_conversion_p for it returns false (its only
argument is the already computed 'this' argument).  This is not a huge
deal, but it causes us to longer accept the call with -fpermissive.

So if we have a non-strictly viable template candidate that has not been
instantiated, then we need to add it to 'bad_fns' even if it doesn't
have any missing conversions.

PR c++/106760

gcc/cp/ChangeLog:

* call.cc (add_candidates): Relax test for adding a candidate
to 'bad_fns' to accept an uninstantiated template candidate that
has no missing conversions.

gcc/testsuite/ChangeLog:

* g++.dg/ext/conv3.C: New test.
---
 gcc/cp/call.cc   |  3 ++-
 gcc/testsuite/g++.dg/ext/conv3.C | 16 
 2 files changed, 18 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/conv3.C

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 2736f55f229..dbf42567cc9 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -6632,7 +6632,8 @@ add_candidates (tree fns, tree first_arg, const vec *args,
 
   if (cand->viable == -1
  && shortcut_bad_convs
- && missing_conversion_p (cand))
+ && (TREE_CODE (cand->fn) == TEMPLATE_DECL
+ || 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/testsuite/g++.dg/ext/conv3.C b/gcc/testsuite/g++.dg/ext/conv3.C
new file mode 100644
index 000..5f4b4d4cc50
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/conv3.C
@@ -0,0 +1,16 @@
+// PR c++/106760
+// { dg-additional-options "-fpermissive" }
+
+struct S {
+  template
+  int f(...);
+
+  int g() const {
+return f(); // { dg-warning "discards qualifiers" }
+  }
+};
+
+int main() {
+  S s;
+  s.g();
+}
-- 
2.41.0.rc1.10.g9e49351c30



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

2023-06-02 Thread Patrick Palka via Gcc-patches
On Thu, 1 Jun 2023, Patrick Palka wrote:

> For a complex alias template-id, dependent_alias_template_spec_p returns
> true if any template argument of the template-id is dependent.  This
> predicate indicates that substitution into the template-id may behave
> differently with respect to SFINAE than substitution into the expanded
> alias, and so the alias is in a way non-transparent.  For example
> 'first_t' in
> 
>   template using first_t = T;
>   template first_t f();
> 
> is such an alias template-id since first_t doesn't use its second
> template parameter and so the substitution into the expanded alias would
> discard the SFINAE effects of the corresponding (dependent) argument 'T&'.
> 
> But this predicate is overly conservative since what really matters for
> sake of SFINAE equivalence is whether a template argument corresponding
> to an _unused_ template parameter is dependent.  So the predicate should
> return false for e.g. 'first_t' or 'first_t'.
> 
> This patch refines the predicate appropriately.  We need to be able to
> efficiently determine which template parameters of a complex alias
> template are unused, so to that end we add a new out parameter to
> complex_alias_template_p and cache its result in an on-the-side
> hash_map that replaces the existing TEMPLATE_DECL_COMPLEX_ALIAS_P
> flag.  And in doing so, we fix a latent bug that this flag wasn't
> being propagated during partial instantiation, and so we were treating
> all partially instantiated member alias templates as non-complex.

Whoops, this last sentence is wrong I think.  The flag propagation would
have happened via the call to copy_decl from tsubst_template_decl, so
there was no latent bug.

> 
>   PR c++/90679
> 
> gcc/cp/ChangeLog:
> 
>   * cp-tree.h (TEMPLATE_DECL_COMPLEX_ALIAS_P): Remove.
>   (most_general_template): Constify parameter.
>   * pt.cc (push_template_decl): Adjust after removing
>   TEMPLATE_DECL_COMPLEX_ALIAS_P.
>   (complex_alias_tmpl_info): New hash_map.
>   (uses_all_template_parms_data::seen): Change type to
>   tree* from bool*.
>   (complex_alias_template_r): Adjust accordingly.
>   (complex_alias_template_p): Add 'seen_out' out parameter.
>   Call most_general_template and check PRIMARY_TEMPLATE_P.
>   Use complex_alias_tmpl_info to cache the result and set
>   '*seen_out' accordigly.
>   (dependent_alias_template_spec_p): Add !processing_template_decl
>   early exit test.  Consider dependence of only template arguments
>   corresponding to seen template parameters as per
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp0x/alias-decl-75.C: New test.
> ---
>  gcc/cp/cp-tree.h   |   7 +-
>  gcc/cp/pt.cc   | 101 +++--
>  gcc/testsuite/g++.dg/cpp0x/alias-decl-75.C |  24 +
>  3 files changed, 100 insertions(+), 32 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-75.C
> 
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index a1b882f11fe..5330d1e1f62 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -543,7 +543,6 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
> 2: DECL_THIS_EXTERN (in VAR_DECL, FUNCTION_DECL or PARM_DECL)
>DECL_IMPLICIT_TYPEDEF_P (in a TYPE_DECL)
>DECL_CONSTRAINT_VAR_P (in a PARM_DECL)
> -  TEMPLATE_DECL_COMPLEX_ALIAS_P (in TEMPLATE_DECL)
>DECL_INSTANTIATING_NSDMI_P (in a FIELD_DECL)
>USING_DECL_UNRELATED_P (in USING_DECL)
> 3: DECL_IN_AGGR_P.
> @@ -3655,10 +3654,6 @@ struct GTY(()) lang_decl {
>  #define TYPE_DECL_ALIAS_P(NODE) \
>DECL_LANG_FLAG_6 (TYPE_DECL_CHECK (NODE))
>  
> -/* Nonzero for TEMPLATE_DECL means that it is a 'complex' alias template.  */
> -#define TEMPLATE_DECL_COMPLEX_ALIAS_P(NODE) \
> -  DECL_LANG_FLAG_2 (TEMPLATE_DECL_CHECK (NODE))
> -
>  /* Nonzero for a type which is an alias for another type; i.e, a type
> which declaration was written 'using name-of-type =
> another-type'.  */
> @@ -7403,7 +7398,7 @@ extern tree tsubst_argument_pack(tree, 
> tree, tsubst_flags_t, tree);
>  extern tree tsubst_template_args (tree, tree, tsubst_flags_t, 
> tree);
>  extern tree tsubst_template_arg  (tree, tree, 
> tsubst_flags_t, tree);
>  extern tree tsubst_function_parms(tree, tree, tsubst_flags_t, 
> tree);
> -extern tree most_general_template(tree);
> +extern tree most_general_template(const_tree);
>  extern tree get_mostly_instantiated_function_type (tree);
>  extern bool problematic_instantiation_changed(void);
>  extern void record_last_problematic_instantiation (void);
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 7fb3e75bceb..1b28195e10d 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -211,7 +211,6 @@ static tree listify (tree);
>  static tree listify_autos (tree, tree);
>  static tree tsubst_template_parm (tree, tree, tsubst_flags_t);
>  st

[PATCH] c++: extend lookup_template_class shortcut [PR110122]

2023-06-05 Thread Patrick Palka via Gcc-patches
Here when substituting the injected class name A during regeneration of
the lambda, we find ourselves in lookup_template_class for A with
V=_ZTAXtl3BarEE (i.e. the template parameter object for Foo{}).  The
call to coerce_template_parms within then undesirably tries to make a copy
of this class NTTP argument, which fails because its type is not copyable.

Sidestepping the question of when precisely a class NTTP should be
copied (which is the subject of PR104577), it seems clear that this
testcase shouldn't require copyability of Foo.

lookup_template_class has a shortcut for looking up the current class
scope, which would avoid the problematic coerce_template_parms call, but
the shortcut doesn't trigger because it only considers the innermost
class scope which in this case in the lambda type.  So this patch fixes
this by extending the lookup_template_class shortcut to consider outer
class scopes too (and skipping over lambda types since they are never
instantiated from lookup_template_class IIUC).  We also need to avoid
calling coerce_template_parms when looking up a templated non-template
class for sake of the A::B example.  The call should be unnecessary
because the innermost arguments belong to the context and so should have
already been coerced.

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?  To fix the 13 regression in that PR, it should suffice to do a
minimal backport of this change that just replaces current_class_type
with current_nonlambda_class_type in the shortcut.

PR c++/110122
PR c++/104577

gcc/cp/ChangeLog:

* pt.cc (lookup_template_class): Extend shortcut for looking
up the current class scope to consider outer class scopes too,
and use current_nonlambda_class_type instead of current_class_type.
Only call coerce_template_parms when looking up a true class
template.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/nontype-class57.C: New test.
---
 gcc/cp/pt.cc | 19 +++
 gcc/testsuite/g++.dg/cpp2a/nontype-class57.C | 25 
 2 files changed, 40 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class57.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 244b0b03454..29ad9ba4072 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -9928,16 +9928,27 @@ lookup_template_class (tree d1, tree arglist, tree 
in_decl, tree context,
 template.  */
 
   /* Shortcut looking up the current class scope again.  */
-  if (current_class_type)
-   if (tree ti = CLASSTYPE_TEMPLATE_INFO (current_class_type))
+  for (tree scope = current_nonlambda_class_type ();
+  scope != NULL_TREE;
+  scope = TYPE_P (scope) ? TYPE_CONTEXT (scope) : DECL_CONTEXT (scope))
+   {
+ if (!CLASS_TYPE_P (scope))
+   continue;
+
+ tree ti = CLASSTYPE_TEMPLATE_INFO (scope);
+ if (!ti || TMPL_ARGS_DEPTH (TI_ARGS (ti)) < arg_depth)
+   break;
+
  if (gen_tmpl == most_general_template (TI_TEMPLATE (ti))
  && comp_template_args (arglist, TI_ARGS (ti)))
-   return current_class_type;
+   return scope;
+   }
 
   /* Calculate the BOUND_ARGS.  These will be the args that are
 actually tsubst'd into the definition to create the
 instantiation.  */
-  arglist = coerce_template_parms (parmlist, arglist, gen_tmpl, complain);
+  if (PRIMARY_TEMPLATE_P (gen_tmpl))
+   arglist = coerce_template_parms (parmlist, arglist, gen_tmpl, complain);
 
   if (arglist == error_mark_node)
/* We were unable to bind the arguments.  */
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class57.C 
b/gcc/testsuite/g++.dg/cpp2a/nontype-class57.C
new file mode 100644
index 000..88ebdc1b3ff
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class57.C
@@ -0,0 +1,25 @@
+// PR c++/110122
+// { dg-do compile { target c++20 } }
+
+struct Foo {
+  constexpr Foo() = default;
+  Foo(const Foo&) = delete;
+};
+
+template
+struct A {
+  A() {
+[] { A a; }();
+[this] { this; }();
+  }
+
+  struct B {
+B() {
+  [] { A a; }();
+  [this] { this; }();
+}
+  };
+};
+
+A a;
+A::B b;
-- 
2.41.0.rc1.10.g9e49351c30



[PATCH] c++: unsynthesized defaulted constexpr fn [PR110122]

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

-- >8 --

In the second testcase of PR110122, during regeneration of the generic
lambda with V=Bar{}, substitution followed by coerce_template_parms for
A's template argument naturally yields a copy of V in terms of Bar's
(implicitly) defaulted copy constructor.

This however happens inside a template context so although we introduced
a use of the copy constructor, mark_used didn't actually synthesize it,
which causes subsequent constant evaluation of the template argument to
fail with:

  nontype-class58.C: In instantiation of ‘void f() [with Bar V = Bar{Foo()}]’:
  nontype-class58.C:22:11:   required from here
  nontype-class58.C:18:18: error: ‘constexpr Bar::Bar(const Bar&)’ used before 
its definition

Conveniently we already make sure to instantiate eligible constexpr
functions before such (manifestly) constant evaluation, as per P0859R0.
So this patch fixes this by making sure to synthesize eligible defaulted
constexpr functions beforehand as well.

PR c++/110122

gcc/cp/ChangeLog:

* constexpr.cc (instantiate_cx_fn_r): Also synthesize defaulted
functions.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/nontype-class58.C: New test.
---
 gcc/cp/constexpr.cc  |  7 --
 gcc/testsuite/g++.dg/cpp2a/nontype-class58.C | 23 
 2 files changed, 28 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class58.C

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 8f7f0b7d325..a7efebcded1 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -8110,11 +8110,14 @@ instantiate_cx_fn_r (tree *tp, int *walk_subtrees, void 
*/*data*/)
   && DECL_DECLARED_CONSTEXPR_P (*tp)
   && !DECL_INITIAL (*tp)
   && !trivial_fn_p (*tp)
-  && DECL_TEMPLOID_INSTANTIATION (*tp)
+  && (DECL_TEMPLOID_INSTANTIATION (*tp) || DECL_DEFAULTED_FN (*tp))
   && !uid_sensitive_constexpr_evaluation_p ())
 {
   ++function_depth;
-  instantiate_decl (*tp, /*defer_ok*/false, /*expl_inst*/false);
+  if (DECL_TEMPLOID_INSTANTIATION (*tp))
+   instantiate_decl (*tp, /*defer_ok*/false, /*expl_inst*/false);
+  else
+   synthesize_method (*tp);
   --function_depth;
 }
   else if (TREE_CODE (*tp) == CALL_EXPR
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class58.C 
b/gcc/testsuite/g++.dg/cpp2a/nontype-class58.C
new file mode 100644
index 000..6e40698da2f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class58.C
@@ -0,0 +1,23 @@
+// PR c++/110122
+// { dg-do compile { target c++20 } }
+
+struct Foo {
+  Foo() = default;
+  constexpr Foo(const Foo&) { }
+};
+
+struct Bar {
+  Foo _;
+};
+
+template
+struct A { };
+
+template
+void f() {
+  [](auto){ A d; }(0); // { dg-bogus "used before its definition" }
+};
+
+int main() {
+  f();
+}
-- 
2.41.0.rc1.10.g9e49351c30



Re: [PATCH] c++: unsynthesized defaulted constexpr fn [PR110122]

2023-06-08 Thread Patrick Palka via Gcc-patches
On Wed, 7 Jun 2023, Jason Merrill wrote:

> On 6/6/23 14:29, Patrick Palka wrote:
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > trunk?
> > 
> > -- >8 --
> > 
> > In the second testcase of PR110122, during regeneration of the generic
> > lambda with V=Bar{}, substitution followed by coerce_template_parms for
> > A's template argument naturally yields a copy of V in terms of Bar's
> > (implicitly) defaulted copy constructor.
> > 
> > This however happens inside a template context so although we introduced
> > a use of the copy constructor, mark_used didn't actually synthesize it,
> > which causes subsequent constant evaluation of the template argument to
> > fail with:
> > 
> >nontype-class58.C: In instantiation of ‘void f() [with Bar V =
> > Bar{Foo()}]’:
> >nontype-class58.C:22:11:   required from here
> >nontype-class58.C:18:18: error: ‘constexpr Bar::Bar(const Bar&)’ used
> > before its definition
> > 
> > Conveniently we already make sure to instantiate eligible constexpr
> > functions before such (manifestly) constant evaluation, as per P0859R0.
> > So this patch fixes this by making sure to synthesize eligible defaulted
> > constexpr functions beforehand as well.
> 
> We probably also want to do this in cxx_eval_call_expression, under

Makes sense, like so?  I'm not sure if it's possible to write a test
for which this code path makes an observable difference, but I verified
the code path is hit a couple of times throughout the testsuite (mainly
from fold_non_dependent_expr called from build_non_dependent_expr).
Bootstrapped and regtested on x86_64-pc-linux-gnu.

-->8 --

PR c++/110122

gcc/cp/ChangeLog:

* constexpr.cc (cxx_eval_call_expression): Also synthesize
eligible defaulted functions.
(instantiate_cx_fn_r): Likewise.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/nontype-class58.C: New test.
---
 gcc/cp/constexpr.cc  | 14 
 gcc/testsuite/g++.dg/cpp2a/nontype-class58.C | 23 
 2 files changed, 33 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class58.C

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 8f7f0b7d325..9122a5efa65 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -2897,7 +2897,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree 
t,
 
   /* We can't defer instantiating the function any longer.  */
   if (!DECL_INITIAL (fun)
-  && DECL_TEMPLOID_INSTANTIATION (fun)
+  && (DECL_TEMPLOID_INSTANTIATION (fun) || DECL_DEFAULTED_FN (fun))
   && !uid_sensitive_constexpr_evaluation_p ())
 {
   location_t save_loc = input_location;
@@ -2905,7 +2905,10 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree 
t,
   ++function_depth;
   if (ctx->manifestly_const_eval == mce_true)
FNDECL_MANIFESTLY_CONST_EVALUATED (fun) = true;
-  instantiate_decl (fun, /*defer_ok*/false, /*expl_inst*/false);
+  if (DECL_TEMPLOID_INSTANTIATION (fun))
+   instantiate_decl (fun, /*defer_ok*/false, /*expl_inst*/false);
+  else
+   synthesize_method (fun);
   --function_depth;
   input_location = save_loc;
 }
@@ -8110,11 +8113,14 @@ instantiate_cx_fn_r (tree *tp, int *walk_subtrees, void 
*/*data*/)
   && DECL_DECLARED_CONSTEXPR_P (*tp)
   && !DECL_INITIAL (*tp)
   && !trivial_fn_p (*tp)
-  && DECL_TEMPLOID_INSTANTIATION (*tp)
+  && (DECL_TEMPLOID_INSTANTIATION (*tp) || DECL_DEFAULTED_FN (*tp))
   && !uid_sensitive_constexpr_evaluation_p ())
 {
   ++function_depth;
-  instantiate_decl (*tp, /*defer_ok*/false, /*expl_inst*/false);
+  if (DECL_TEMPLOID_INSTANTIATION (*tp))
+   instantiate_decl (*tp, /*defer_ok*/false, /*expl_inst*/false);
+  else
+   synthesize_method (*tp);
   --function_depth;
 }
   else if (TREE_CODE (*tp) == CALL_EXPR
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class58.C 
b/gcc/testsuite/g++.dg/cpp2a/nontype-class58.C
new file mode 100644
index 000..6e40698da2f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class58.C
@@ -0,0 +1,23 @@
+// PR c++/110122
+// { dg-do compile { target c++20 } }
+
+struct Foo {
+  Foo() = default;
+  constexpr Foo(const Foo&) { }
+};
+
+struct Bar {
+  Foo _;
+};
+
+template
+struct A { };
+
+template
+void f() {
+  [](auto){ A d; }(0); // { dg-bogus "used before its definition" }
+};
+
+int main() {
+  f();
+}
-- 
2.41.0.rc1.10.g9e49351c30


> 
> >   /* We can't defer instantiating the function any longer.  */
> 
> Jason
> 
> 


[PATCH] c++: diagnostic ICE b/c of empty TPARMS_PRIMARY_TEMPLATE [PR109655]

2023-06-09 Thread Patrick Palka via Gcc-patches
When defining a previously declared class template, we neglect to set
TPARMS_PRIMARY_TEMPLATE for the in-scope template parameters, which the
class members go on to inherit, and so the members' DECL_TEMPLATE_PARMS
will have empty TPARMS_PRIMARY_TEMPLATE at those levels as well.  This
causes us to crash when diagnosing a constraint mismatch for an
out-of-line declaration of a member of a constrained class template.

This patch fixes this by walking the context to get at the corresponding
primary template instead.  I spent a while trying to get us to set
TPARMS_PRIMARY_TEMPLATE for templated class definitions that are
redeclarations, but it proved to be hairy in particular for partial
specializations and nested templates.

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

PR c++/109655

gcc/cp/ChangeLog:

* pt.cc (push_template_decl): Handle TPARMS_PRIMARY_TEMPLATE
being empty when diagnosing a constraint mismatch for an
enclosing template scope.  Don't bother checking constraints
if DECL_PARMS and SCOPE_PARMS are the same.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts-class6.C: New test.
* g++.dg/cpp2a/concepts-class6a.C: New test.
---
 gcc/cp/pt.cc  | 19 +++--
 gcc/testsuite/g++.dg/cpp2a/concepts-class6.C  | 30 ++
 gcc/testsuite/g++.dg/cpp2a/concepts-class6a.C | 40 +++
 3 files changed, 86 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-class6.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-class6a.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 17bf4d24151..f913b248345 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -6155,12 +6155,25 @@ push_template_decl (tree decl, bool is_friend)
  decl_parms = TREE_CHAIN (decl_parms);
  scope_parms = TREE_CHAIN (scope_parms);
}
- while (decl_parms)
+ while (decl_parms && decl_parms != scope_parms)
{
  if (!template_requirements_equivalent_p (decl_parms, scope_parms))
{
- error ("redeclaration of %qD with different constraints",
-TPARMS_PRIMARY_TEMPLATE (TREE_VALUE (decl_parms)));
+ tree td = TPARMS_PRIMARY_TEMPLATE (TREE_VALUE (decl_parms));
+ if (!td)
+   {
+ /* FIXME: TPARMS_PRIMARY_TEMPLATE doesn't always get
+set for enclosing template scopes.  Work around
+this by walking the context to obtain the relevant
+(primary) template whose constraints we mismatch.  */
+ int level = TMPL_PARMS_DEPTH (decl_parms);
+ td = TYPE_TI_TEMPLATE (ctx);
+ while (!PRIMARY_TEMPLATE_P (td)
+|| (TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (td))
+!= level))
+   td = TYPE_TI_TEMPLATE (DECL_CONTEXT (td));
+   }
+ error ("redeclaration of %qD with different constraints", td);
  break;
}
  decl_parms = TREE_CHAIN (decl_parms);
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-class6.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-class6.C
new file mode 100644
index 000..dcef6a2c9d4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-class6.C
@@ -0,0 +1,30 @@
+// PR c++/109655
+// { dg-do compile { target c++20 } }
+
+class C {
+  template
+  requires true
+  friend class D;
+
+  template
+  requires true
+  class E;
+};
+
+template
+requires true
+class D {
+  void f();
+};
+
+template
+void D::f() { } // { dg-error "class D' with different constraints" }
+
+template
+requires true
+class C::E {
+  void f();
+};
+
+template
+void C::E::f() { } // { dg-error "class C::E' with different constraints" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-class6a.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-class6a.C
new file mode 100644
index 000..751d13cdf6c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-class6a.C
@@ -0,0 +1,40 @@
+// PR c++/109655
+// { dg-do compile { target c++20 } }
+
+template
+requires true
+class C {
+  class D;
+
+  template
+  requires (!!true)
+  class E;
+};
+
+template
+requires true
+class C::D {
+  void f();
+};
+
+template  // missing "requires true"
+void C::D::f() { } // { dg-error "class C' with different constraints" }
+
+template
+requires true
+template
+requires (!!true)
+class C::E {
+  void f();
+  void g();
+};
+
+template
+requires true
+template
+void C::E::f() { } // { dg-error "class C::E' with different 
constraints" }
+
+template
+template
+requires (!!true)
+void C::E::g() { } // { dg-error "class C' with different constraints" }
-- 
2.41.0.rc1.10.g9e49351c30



Re: [PATCH v3 4/6] libstdc++: use new built-in trait __is_function for std::is_function

2023-06-09 Thread Patrick Palka via Gcc-patches
On Sun, 2 Apr 2023, Ken Matsui via Gcc-patches wrote:

> This patch gets std::is_function to dispatch to new built-in trait
> __is_function.

For std::is_function and other predicate-like type traits, I think we also
want to make the corresponding variable template is_function_v directly
use the built-in too.

> 
> libstdc++-v3/ChangeLog:
> 
>   * include/std/type_traits (is_function): Use __is_function built-in
>   trait.
> 
> Signed-off-by: Ken Matsui 
> ---
>  libstdc++-v3/include/std/type_traits | 7 +++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/libstdc++-v3/include/std/type_traits 
> b/libstdc++-v3/include/std/type_traits
> index 58a732735c8..9eafd6b16f2 100644
> --- a/libstdc++-v3/include/std/type_traits
> +++ b/libstdc++-v3/include/std/type_traits
> @@ -594,6 +594,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>  { };
>  
>/// is_function
> +#if __has_builtin(__is_function)
> +  template
> +struct is_function
> +: public __bool_constant<__is_function(_Tp)>
> +{ };
> +#else
>template
>  struct is_function
>  : public __bool_constant::value> { };
> @@ -605,6 +611,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>template
>  struct is_function<_Tp&&>
>  : public false_type { };
> +#endif
>  
>  #define __cpp_lib_is_null_pointer 201309L
>  
> -- 
> 2.40.0
> 
> 



[PATCH] c++: constrained surrogate calls [PR110535]

2023-07-12 Thread Patrick Palka via Gcc-patches
We're not checking constraints of pointer/reference-to-function conversion
functions during overload resolution, which causes us to ICE on the first
testcase and incorrectly reject the second testcase.

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

PR c++/110535

gcc/cp/ChangeLog:

* call.cc (add_conv_candidate): Check constraints.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts-surrogate1.C: New test.
* g++.dg/cpp2a/concepts-surrogate2.C: New test.
---
 gcc/cp/call.cc   |  8 
 gcc/testsuite/g++.dg/cpp2a/concepts-surrogate1.C | 12 
 gcc/testsuite/g++.dg/cpp2a/concepts-surrogate2.C | 14 ++
 3 files changed, 34 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-surrogate1.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-surrogate2.C

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 15a3d6f2a1f..81935b83908 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -2588,6 +2588,14 @@ add_conv_candidate (struct z_candidate **candidates, 
tree fn, tree obj,
   if (*candidates && (*candidates)->fn == totype)
 return NULL;
 
+  if (!constraints_satisfied_p (fn))
+{
+  reason = constraint_failure ();
+  viable = 0;
+  return add_candidate (candidates, fn, obj, arglist, len, convs,
+   access_path, conversion_path, viable, reason, 
flags);
+}
+
   for (i = 0; i < len; ++i)
 {
   tree arg, argtype, convert_type = NULL_TREE;
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-surrogate1.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-surrogate1.C
new file mode 100644
index 000..e8481a31656
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-surrogate1.C
@@ -0,0 +1,12 @@
+// PR c++/110535
+// { dg-do compile { target c++20 } }
+
+using F = int(int);
+
+template
+struct A {
+ operator F*() requires B;
+};
+
+int i = A{}(0);  // OK
+int j = A{}(0); // { dg-error "no match" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-surrogate2.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-surrogate2.C
new file mode 100644
index 000..8bf8364beb7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-surrogate2.C
@@ -0,0 +1,14 @@
+// PR c++/110535
+// { dg-do compile { target c++20 } }
+
+using F = int(int);
+using G = long(int);
+
+template
+struct A {
+ operator F&() requires B;
+ operator G&() requires (!B);
+};
+
+int i = A{}(0);  // { dg-bogus "ambiguous" }
+int j = A{}(0); // { dg-bogus "ambiguous" }
-- 
2.41.0.327.gaa9166bcc0



Re: [PATCH] c++: constrained surrogate calls [PR110535]

2023-07-12 Thread Patrick Palka via Gcc-patches
On Wed, 12 Jul 2023, Patrick Palka wrote:

> We're not checking constraints of pointer/reference-to-function conversion
> functions during overload resolution, which causes us to ICE on the first
> testcase and incorrectly reject the second testcase.

Er, I noticed [over.call.object] doesn't exactly say that surrogate
call functions inherit the constraints of the corresponding conversion
function, but I reckon that's the intent?

> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk/13?
> 
>   PR c++/110535
> 
> gcc/cp/ChangeLog:
> 
>   * call.cc (add_conv_candidate): Check constraints.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp2a/concepts-surrogate1.C: New test.
>   * g++.dg/cpp2a/concepts-surrogate2.C: New test.
> ---
>  gcc/cp/call.cc   |  8 
>  gcc/testsuite/g++.dg/cpp2a/concepts-surrogate1.C | 12 
>  gcc/testsuite/g++.dg/cpp2a/concepts-surrogate2.C | 14 ++
>  3 files changed, 34 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-surrogate1.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-surrogate2.C
> 
> diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
> index 15a3d6f2a1f..81935b83908 100644
> --- a/gcc/cp/call.cc
> +++ b/gcc/cp/call.cc
> @@ -2588,6 +2588,14 @@ add_conv_candidate (struct z_candidate **candidates, 
> tree fn, tree obj,
>if (*candidates && (*candidates)->fn == totype)
>  return NULL;
>  
> +  if (!constraints_satisfied_p (fn))
> +{
> +  reason = constraint_failure ();
> +  viable = 0;
> +  return add_candidate (candidates, fn, obj, arglist, len, convs,
> + access_path, conversion_path, viable, reason, 
> flags);
> +}
> +
>for (i = 0; i < len; ++i)
>  {
>tree arg, argtype, convert_type = NULL_TREE;
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-surrogate1.C 
> b/gcc/testsuite/g++.dg/cpp2a/concepts-surrogate1.C
> new file mode 100644
> index 000..e8481a31656
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-surrogate1.C
> @@ -0,0 +1,12 @@
> +// PR c++/110535
> +// { dg-do compile { target c++20 } }
> +
> +using F = int(int);
> +
> +template
> +struct A {
> + operator F*() requires B;
> +};
> +
> +int i = A{}(0);  // OK
> +int j = A{}(0); // { dg-error "no match" }
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-surrogate2.C 
> b/gcc/testsuite/g++.dg/cpp2a/concepts-surrogate2.C
> new file mode 100644
> index 000..8bf8364beb7
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-surrogate2.C
> @@ -0,0 +1,14 @@
> +// PR c++/110535
> +// { dg-do compile { target c++20 } }
> +
> +using F = int(int);
> +using G = long(int);
> +
> +template
> +struct A {
> + operator F&() requires B;
> + operator G&() requires (!B);
> +};
> +
> +int i = A{}(0);  // { dg-bogus "ambiguous" }
> +int j = A{}(0); // { dg-bogus "ambiguous" }
> -- 
> 2.41.0.327.gaa9166bcc0
> 
> 



[PATCH] c++: non-standalone surrogate call template

2023-07-12 Thread Patrick Palka via Gcc-patches
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?  There might be an existing PR for this issue but Bugzilla search
seems to be timing out for me currently.

-- >8 --

I noticed we were accidentally preventing ourselves from considering
a pointer/reference-to-function conversion function template if it's
not the first conversion function that's considered, which for the
testcase below resulted in us accepting the B call but not the A call
despite the only difference between A and B being the order of member
declarations.  This patch fixes this so that the outcome of overload
resolution doesn't arbitrarily depend on declaration order in this
situation.

gcc/cp/ChangeLog:

* call.cc (add_template_conv_candidate): Don't check for
non-empty 'candidates' here.
(build_op_call): Check it here, before we've considered any
conversion functions.

gcc/testsuite/ChangeLog:

* g++.dg/overload/conv-op5.C: New test.
---
 gcc/cp/call.cc   | 24 ++--
 gcc/testsuite/g++.dg/overload/conv-op5.C | 18 ++
 2 files changed, 32 insertions(+), 10 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/overload/conv-op5.C

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 81935b83908..119063979fa 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -3709,12 +3709,6 @@ add_template_conv_candidate (struct z_candidate 
**candidates, tree tmpl,
 tree return_type, tree access_path,
 tree conversion_path, tsubst_flags_t complain)
 {
-  /* Making this work broke PR 71117 and 85118, so until the committee resolves
- core issue 2189, let's disable this candidate if there are any call
- operators.  */
-  if (*candidates)
-return NULL;
-
   return
 add_template_candidate_real (candidates, tmpl, NULL_TREE, NULL_TREE,
 NULL_TREE, arglist, return_type, access_path,
@@ -5290,6 +5284,8 @@ build_op_call (tree obj, vec **args, 
tsubst_flags_t complain)
  LOOKUP_NORMAL, &candidates, complain);
 }
 
+  bool any_call_ops = candidates != nullptr;
+
   convs = lookup_conversions (type);
 
   for (; convs; convs = TREE_CHAIN (convs))
@@ -5306,10 +5302,18 @@ build_op_call (tree obj, vec **args, 
tsubst_flags_t complain)
  continue;
 
if (TREE_CODE (fn) == TEMPLATE_DECL)
- add_template_conv_candidate
-   (&candidates, fn, obj, *args, totype,
-/*access_path=*/NULL_TREE,
-/*conversion_path=*/NULL_TREE, complain);
+ {
+   /* Making this work broke PR 71117 and 85118, so until the
+  committee resolves core issue 2189, let's disable this
+  candidate if there are any call operators.  */
+   if (any_call_ops)
+ continue;
+
+   add_template_conv_candidate
+ (&candidates, fn, obj, *args, totype,
+  /*access_path=*/NULL_TREE,
+  /*conversion_path=*/NULL_TREE, complain);
+ }
else
  add_conv_candidate (&candidates, fn, obj,
  *args, /*conversion_path=*/NULL_TREE,
diff --git a/gcc/testsuite/g++.dg/overload/conv-op5.C 
b/gcc/testsuite/g++.dg/overload/conv-op5.C
new file mode 100644
index 000..b7724908b62
--- /dev/null
+++ b/gcc/testsuite/g++.dg/overload/conv-op5.C
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++11 } }
+
+template using F = int(*)(T);
+using G = int(*)(int*);
+
+struct A {
+  template operator F();  // #1
+  operator G() = delete; // #2
+};
+
+int i = A{}(0); // selects #1
+
+struct B {
+  operator G() = delete; // #2
+  template operator F();  // #1
+};
+
+int j = B{}(0); // selects #1
-- 
2.41.0.327.gaa9166bcc0



[PATCH] c++: mangling template-id of unknown template [PR110524]

2023-07-13 Thread Patrick Palka via Gcc-patches
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
for trunk and perhaps 13?

-- >8 --

This fixes a crash when mangling an ADL-enabled call to a template-id
naming an unknown template (as per P0846R0).

PR c++/110524

gcc/cp/ChangeLog:

* mangle.cc (write_expression): Handle TEMPLATE_ID_EXPR
whose template is already an IDENTIFIER_NODE.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/fn-template26.C: New test.
---
 gcc/cp/mangle.cc   |  3 ++-
 gcc/testsuite/g++.dg/cpp2a/fn-template26.C | 16 
 2 files changed, 18 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/fn-template26.C

diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
index 7dab4e62bc9..bef0fda6d22 100644
--- a/gcc/cp/mangle.cc
+++ b/gcc/cp/mangle.cc
@@ -3312,7 +3312,8 @@ write_expression (tree expr)
   else if (TREE_CODE (expr) == TEMPLATE_ID_EXPR)
 {
   tree fn = TREE_OPERAND (expr, 0);
-  fn = OVL_NAME (fn);
+  if (!identifier_p (fn))
+   fn = OVL_NAME (fn);
   if (IDENTIFIER_ANY_OP_P (fn))
write_string ("on");
   write_unqualified_id (fn);
diff --git a/gcc/testsuite/g++.dg/cpp2a/fn-template26.C 
b/gcc/testsuite/g++.dg/cpp2a/fn-template26.C
new file mode 100644
index 000..d4a17eb9bd1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/fn-template26.C
@@ -0,0 +1,16 @@
+// PR c++/110524
+// { dg-do compile { target c++20 } }
+
+template
+auto f(T t) -> decltype(g(t));
+
+namespace N {
+  struct A { };
+  template void g(T);
+};
+
+int main() {
+  f(N::A{});
+}
+
+// { dg-final { scan-assembler "_Z1fIN1N1AEEDTcl1gIT_Efp_EES2_" } }
-- 
2.41.0.327.gaa9166bcc0



Re: [PATCH] c++: redundant targ coercion for var/alias tmpls

2023-07-13 Thread Patrick Palka via Gcc-patches
On Wed, 28 Jun 2023, Patrick Palka wrote:

> On Wed, Jun 28, 2023 at 11:50 AM Jason Merrill  wrote:
> >
> > On 6/23/23 12:23, Patrick Palka wrote:
> > > On Fri, 23 Jun 2023, Jason Merrill wrote:
> > >
> > >> On 6/21/23 13:19, Patrick Palka wrote:
> > >>> When stepping through the variable/alias template specialization code
> > >>> paths, I noticed we perform template argument coercion twice: first from
> > >>> instantiate_alias_template / finish_template_variable and again from
> > >>> tsubst_decl (during instantiate_template).  It should suffice to perform
> > >>> coercion once.
> > >>>
> > >>> To that end patch elides this second coercion from tsubst_decl when
> > >>> possible.  We can't get rid of it completely because we don't always
> > >>> specialize a variable template from finish_template_variable: we could
> > >>> also be doing so directly from instantiate_template during variable
> > >>> template partial specialization selection, in which case the coercion
> > >>> from tsubst_decl would be the first and only coercion.
> > >>
> > >> Perhaps we should be coercing in lookup_template_variable rather than
> > >> finish_template_variable?
> > >
> > > Ah yes, there's a patch for that at
> > > https://gcc.gnu.org/pipermail/gcc-patches/2023-May/617377.html :)
> >
> > So after that patch, can we get rid of the second coercion completely?
> 
> On second thought it should be possible to get rid of it, if we
> rearrange things to always pass the primary arguments to tsubst_decl,
> and perform partial specialization selection from there instead of
> instantiate_template.  Let me try...

Like so?  Bootstrapped and regtested on x86_64-pc-linux-gnu.

-- >8 --

When stepping through the variable/alias template specialization code
paths, I noticed we perform template argument coercion twice: first from
instantiate_alias_template / finish_template_variable and again from
tsubst_decl (during instantiate_template).  It'd be good to avoid this
redundant coercion.

It turns out that this coercion could be safely elided whenever
specializing a primary variable/alias template, because we can rely on
lookup_template_variable and instantiate_alias_template to already have
coerced the arguments.

The other situation to consider is when fully specializing a partial
variable template specialization (from instantiate_template), in which
case the passed 'args' are the (already coerced) arguments relative to
the partial template and 'argvec', the result of substitution into
DECL_TI_ARGS, are the (uncoerced) arguments relative to the primary
template, so coercion is still necessary.  We can still avoid this
coercion however if we always pass the primary variable template to
tsubst_decl from instantiate_template, and instead perform partial
specialization selection directly from tsubst_decl.  This patch
implements this approach.

gcc/cp/ChangeLog:

* pt.cc (tsubst_decl) : Don't call
coerce_template_parms.  Call most_specialized_partial_spec
when fully specializing a variable template here ...
(instantiate_template): ... instead of here.  Always pass
the primary variable template pattern to tsubst_decl.
---
 gcc/cp/pt.cc | 62 +++-
 1 file changed, 27 insertions(+), 35 deletions(-)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index fa15b75b9c5..53968b823d5 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -15194,6 +15194,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
/* Check to see if we already have the specialization we
   need.  */
tree spec = NULL_TREE;
+   tree partial_ti = NULL_TREE;
bool local_p = false;
tree ctx = DECL_CONTEXT (t);
if (!(VAR_P (t) && DECL_LOCAL_DECL_P (t))
@@ -15230,17 +15231,29 @@ tsubst_decl (tree t, tree args, tsubst_flags_t 
complain)
tmpl = DECL_TI_TEMPLATE (t);
gen_tmpl = most_general_template (tmpl);
argvec = tsubst (DECL_TI_ARGS (t), args, complain, in_decl);
-   if (argvec != error_mark_node
-   && PRIMARY_TEMPLATE_P (gen_tmpl)
-   && TMPL_ARGS_DEPTH (args) >= TMPL_ARGS_DEPTH (argvec))
- /* We're fully specializing a template declaration, so
-we need to coerce the innermost arguments corresponding to
-the template.  */
- argvec = (coerce_template_parms
-   (DECL_TEMPLATE_PARMS (gen_tmpl),
-argvec, tmpl, complain));
if (argvec == error_mark_node)
  RETURN (error_mark_node);
+   if (variable_template_p (gen_tmpl)
+   && TMPL_ARGS_DEPTH (args) >= TMPL_ARGS_DEPTH (argvec))
+ {
+   /* We need to determine if we're using a partial
+  specialization now, because the type of the
+  variable could be different.  */
+   

[PATCH] c++: copy elision of object arg in static memfn call [PR110441]

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

-- >8 --

Here the call A().f() is represented as a COMPOUND_EXPR whose first
operand is the otherwise unused object argument A() and second operand
is the call result (both are TARGET_EXPRs).  Within the return statement,
this outermost COMPOUND_EXPR ends up foiling the copy elision check in
build_special_member_call, resulting in us introducing a bogus call to the
deleted move constructor.  (Within the variable initialization, which goes
through ocp_convert instead of convert_for_initialization, we've already
been eliding the copy despite the outermost COMPOUND_EXPR ever since
r10-7410-g72809d6fe8e085 made ocp_convert look through COMPOUND_EXPR).

In contrast, I noticed '(A(), A::f())' (which should be equivalent to
the above call) is represented with the COMPOUND_EXPR inside the RHS's
TARGET_EXPR initializer thanks to a special case in cp_build_compound_expr
thus avoiding the issue.

So this patch fixes this by making keep_unused_object_arg
use cp_build_compound_expr as well.

PR c++/110441

gcc/cp/ChangeLog:

* call.cc (keep_unused_object_arg): Use cp_build_compound_expr
instead of building a COMPOUND_EXPR directly.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/elide8.C: New test.
---
 gcc/cp/call.cc  |  2 +-
 gcc/testsuite/g++.dg/cpp1z/elide8.C | 25 +
 2 files changed, 26 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1z/elide8.C

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 119063979fa..b0a69cb46d4 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -5218,7 +5218,7 @@ keep_unused_object_arg (tree result, tree obj, tree fn)
   if (TREE_THIS_VOLATILE (a))
 a = build_this (a);
   if (TREE_SIDE_EFFECTS (a))
-return build2 (COMPOUND_EXPR, TREE_TYPE (result), a, result);
+return cp_build_compound_expr (a, result, tf_warning_or_error);
   return result;
 }
 
diff --git a/gcc/testsuite/g++.dg/cpp1z/elide8.C 
b/gcc/testsuite/g++.dg/cpp1z/elide8.C
new file mode 100644
index 000..7d471be8a2a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/elide8.C
@@ -0,0 +1,25 @@
+// PR c++/110441
+// { dg-do compile { target c++11 } }
+
+struct immovable {
+  immovable(immovable &&) = delete;
+};
+
+struct A {
+  static immovable f();
+};
+
+immovable f() {
+  immovable m = A().f(); // { dg-error "deleted" "" { target c++14_down } }
+  return A().f(); // { dg-error "deleted" "" { target c++14_down } }
+}
+
+struct B {
+  A* operator->();
+};
+
+immovable g() {
+  B b;
+  immovable m = b->f(); // { dg-error "deleted" "" { target c++14_down } }
+  return b->f(); // { dg-error "deleted" "" { target c++14_down } }
+}
-- 
2.41.0.327.gaa9166bcc0



Re: [PATCH] c++: redundant targ coercion for var/alias tmpls

2023-07-14 Thread Patrick Palka via Gcc-patches
On Thu, 13 Jul 2023, Jason Merrill wrote:

> On 7/13/23 11:48, Patrick Palka wrote:
> > On Wed, 28 Jun 2023, Patrick Palka wrote:
> > 
> > > On Wed, Jun 28, 2023 at 11:50 AM Jason Merrill  wrote:
> > > > 
> > > > On 6/23/23 12:23, Patrick Palka wrote:
> > > > > On Fri, 23 Jun 2023, Jason Merrill wrote:
> > > > > 
> > > > > > On 6/21/23 13:19, Patrick Palka wrote:
> > > > > > > When stepping through the variable/alias template specialization
> > > > > > > code
> > > > > > > paths, I noticed we perform template argument coercion twice:
> > > > > > > first from
> > > > > > > instantiate_alias_template / finish_template_variable and again
> > > > > > > from
> > > > > > > tsubst_decl (during instantiate_template).  It should suffice to
> > > > > > > perform
> > > > > > > coercion once.
> > > > > > > 
> > > > > > > To that end patch elides this second coercion from tsubst_decl
> > > > > > > when
> > > > > > > possible.  We can't get rid of it completely because we don't
> > > > > > > always
> > > > > > > specialize a variable template from finish_template_variable: we
> > > > > > > could
> > > > > > > also be doing so directly from instantiate_template during
> > > > > > > variable
> > > > > > > template partial specialization selection, in which case the
> > > > > > > coercion
> > > > > > > from tsubst_decl would be the first and only coercion.
> > > > > > 
> > > > > > Perhaps we should be coercing in lookup_template_variable rather
> > > > > > than
> > > > > > finish_template_variable?
> > > > > 
> > > > > Ah yes, there's a patch for that at
> > > > > https://gcc.gnu.org/pipermail/gcc-patches/2023-May/617377.html :)
> > > > 
> > > > So after that patch, can we get rid of the second coercion completely?
> > > 
> > > On second thought it should be possible to get rid of it, if we
> > > rearrange things to always pass the primary arguments to tsubst_decl,
> > > and perform partial specialization selection from there instead of
> > > instantiate_template.  Let me try...
> > 
> > Like so?  Bootstrapped and regtested on x86_64-pc-linux-gnu.
> > 
> > -- >8 --
> > 
> > When stepping through the variable/alias template specialization code
> > paths, I noticed we perform template argument coercion twice: first from
> > instantiate_alias_template / finish_template_variable and again from
> > tsubst_decl (during instantiate_template).  It'd be good to avoid this
> > redundant coercion.
> > 
> > It turns out that this coercion could be safely elided whenever
> > specializing a primary variable/alias template, because we can rely on
> > lookup_template_variable and instantiate_alias_template to already have
> > coerced the arguments.
> > 
> > The other situation to consider is when fully specializing a partial
> > variable template specialization (from instantiate_template), in which
> > case the passed 'args' are the (already coerced) arguments relative to
> > the partial template and 'argvec', the result of substitution into
> > DECL_TI_ARGS, are the (uncoerced) arguments relative to the primary
> > template, so coercion is still necessary.  We can still avoid this
> > coercion however if we always pass the primary variable template to
> > tsubst_decl from instantiate_template, and instead perform partial
> > specialization selection directly from tsubst_decl.  This patch
> > implements this approach.
> 
> The relationship between instantiate_template and tsubst_decl is pretty
> tangled.  We use the former to substitute (often deduced) template arguments
> into a template, and the latter to substitute template arguments into a use of
> a template...and also to implement the former.
> 
> For substitution of uses of a template, we expect to need to coerce the
> arguments after substitution.  But we avoid this issue for variable templates
> by keeping them as TEMPLATE_ID_EXPR until substitution time, so if we see a
> VAR_DECL in tsubst_decl it's either a non-template variable or under
> instantiate_template.

FWIW it seems we could also be in tsubst_decl for a VAR_DECL if

  * we're partially instantiating a class-scope variable template
during instantiation of the class
  * we're substituting a use of an already non-dependent variable
template specialization

> 
> So it seems like the current coercion for variable templates is only needed in
> this case to support the redundant hash table lookup that we just did in
> instantiate_template.  Perhaps instead of doing coercion here or moving the
> partial spec lookup, we could skip the hash table lookup for the case of a
> variable template?

It seems we'd then also have to make instantiate_template responsible
for registering the variable template specialization since tsubst_decl
no longer necessarily has the arguments relative to the primary template
('args' could be relative to the partial template).

Like so?  The following makes us perform all the specialization table
manipulation in instantiate_template instead of tsubst_decl for variable
template specializations.

Re: [PATCH] c++: redundant targ coercion for var/alias tmpls

2023-07-17 Thread Patrick Palka via Gcc-patches
On Fri, 14 Jul 2023, Jason Merrill wrote:

> On 7/14/23 14:07, Patrick Palka wrote:
> > On Thu, 13 Jul 2023, Jason Merrill wrote:
> > 
> > > On 7/13/23 11:48, Patrick Palka wrote:
> > > > On Wed, 28 Jun 2023, Patrick Palka wrote:
> > > > 
> > > > > On Wed, Jun 28, 2023 at 11:50 AM Jason Merrill 
> > > > > wrote:
> > > > > > 
> > > > > > On 6/23/23 12:23, Patrick Palka wrote:
> > > > > > > On Fri, 23 Jun 2023, Jason Merrill wrote:
> > > > > > > 
> > > > > > > > On 6/21/23 13:19, Patrick Palka wrote:
> > > > > > > > > When stepping through the variable/alias template
> > > > > > > > > specialization
> > > > > > > > > code
> > > > > > > > > paths, I noticed we perform template argument coercion twice:
> > > > > > > > > first from
> > > > > > > > > instantiate_alias_template / finish_template_variable and
> > > > > > > > > again
> > > > > > > > > from
> > > > > > > > > tsubst_decl (during instantiate_template).  It should suffice
> > > > > > > > > to
> > > > > > > > > perform
> > > > > > > > > coercion once.
> > > > > > > > > 
> > > > > > > > > To that end patch elides this second coercion from tsubst_decl
> > > > > > > > > when
> > > > > > > > > possible.  We can't get rid of it completely because we don't
> > > > > > > > > always
> > > > > > > > > specialize a variable template from finish_template_variable:
> > > > > > > > > we
> > > > > > > > > could
> > > > > > > > > also be doing so directly from instantiate_template during
> > > > > > > > > variable
> > > > > > > > > template partial specialization selection, in which case the
> > > > > > > > > coercion
> > > > > > > > > from tsubst_decl would be the first and only coercion.
> > > > > > > > 
> > > > > > > > Perhaps we should be coercing in lookup_template_variable rather
> > > > > > > > than
> > > > > > > > finish_template_variable?
> > > > > > > 
> > > > > > > Ah yes, there's a patch for that at
> > > > > > > https://gcc.gnu.org/pipermail/gcc-patches/2023-May/617377.html :)
> > > > > > 
> > > > > > So after that patch, can we get rid of the second coercion
> > > > > > completely?
> > > > > 
> > > > > On second thought it should be possible to get rid of it, if we
> > > > > rearrange things to always pass the primary arguments to tsubst_decl,
> > > > > and perform partial specialization selection from there instead of
> > > > > instantiate_template.  Let me try...
> > > > 
> > > > Like so?  Bootstrapped and regtested on x86_64-pc-linux-gnu.
> > > > 
> > > > -- >8 --
> > > > 
> > > > When stepping through the variable/alias template specialization code
> > > > paths, I noticed we perform template argument coercion twice: first from
> > > > instantiate_alias_template / finish_template_variable and again from
> > > > tsubst_decl (during instantiate_template).  It'd be good to avoid this
> > > > redundant coercion.
> > > > 
> > > > It turns out that this coercion could be safely elided whenever
> > > > specializing a primary variable/alias template, because we can rely on
> > > > lookup_template_variable and instantiate_alias_template to already have
> > > > coerced the arguments.
> > > > 
> > > > The other situation to consider is when fully specializing a partial
> > > > variable template specialization (from instantiate_template), in which
> > > > case the passed 'args' are the (already coerced) arguments relative to
> > > > the partial template and 'argvec', the result of substitution into
> > > > DECL_TI_ARGS, are the (uncoerced) arguments relative to the primary
> > > > template, so coercion is still necessary.  We can still avoid this
> > > > coercion however if we always pass the primary variable template to
> > > > tsubst_decl from instantiate_template, and instead perform partial
> > > > specialization selection directly from tsubst_decl.  This patch
> > > > implements this approach.
> > > 
> > > The relationship between instantiate_template and tsubst_decl is pretty
> > > tangled.  We use the former to substitute (often deduced) template
> > > arguments
> > > into a template, and the latter to substitute template arguments into a
> > > use of
> > > a template...and also to implement the former.
> > > 
> > > For substitution of uses of a template, we expect to need to coerce the
> > > arguments after substitution.  But we avoid this issue for variable
> > > templates
> > > by keeping them as TEMPLATE_ID_EXPR until substitution time, so if we see
> > > a
> > > VAR_DECL in tsubst_decl it's either a non-template variable or under
> > > instantiate_template.
> > 
> > FWIW it seems we could also be in tsubst_decl for a VAR_DECL if
> > 
> >* we're partially instantiating a class-scope variable template
> >  during instantiation of the class
> 
> Hmm, why don't partial instantiations stay as TEMPLATE_ID_EXPR?

Whoops, I accidentally omitted a crucial word.  The situation is when
partially instantiating a class-scope variable template _declaration_,
e.g. for

  template
  struct A {
template static int v;
  };

  template struct A;

we call ts

[PATCH] c++: deducing empty type vs non-type argument pack

2023-07-18 Thread Patrick Palka via Gcc-patches
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?  Also verified by way of gcc_assert that we never see
TEMPLATE_PARM_INDEX here.

-- >8 --

Within a template parameter list, a non-type template parameter pack is
represented as a PARM_DECL.  But in a couple of spots where we need to
deduce an empty argument pack, we test for TEMPLATE_PARM_INDEX (within a
template parameter list) instead of for PARM_DECL, which means we end up
using TYPE_ARGUMENT_PACK even in the non-type case.  This patch fixes
this (seemingly harmless) bug.

gcc/cp/ChangeLog:

* pt.cc (type_unification_real): Test for PARM_DECL instead
of TEMPLATE_PARM_INDEX to distinguish a type vs non-type
template parameter pack.
(type_targs_deducible_from): Likewise.
---
 gcc/cp/pt.cc | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 3987ffc509a..d342ab5929a 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -23345,7 +23345,7 @@ type_unification_real (tree tparms,
{
  tree arg;
 
- if (TREE_CODE (tparm) == TEMPLATE_PARM_INDEX)
+ if (TREE_CODE (tparm) == PARM_DECL)
{
  arg = make_node (NONTYPE_ARGUMENT_PACK);
  TREE_CONSTANT (arg) = 1;
@@ -30369,7 +30369,7 @@ type_targs_deducible_from (tree tmpl, tree type)
if (template_parameter_pack_p (tparm))
  {
tree arg;
-   if (TREE_CODE (tparm) == TEMPLATE_PARM_INDEX)
+   if (TREE_CODE (tparm) == PARM_DECL)
  {
arg = make_node (NONTYPE_ARGUMENT_PACK);
TREE_CONSTANT (arg) = 1;
-- 
2.41.0.363.g5e238546dc



Re: [PATCH] c++: fix ICE with is_really_empty_class [PR110106]

2023-07-19 Thread Patrick Palka via Gcc-patches
On Tue, 18 Jul 2023, Marek Polacek via Gcc-patches wrote:

> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk and branches?

Looks reasonable to me.

Though I wonder if we could also fix this by not checking potentiality
at all in this case?  The problematic call to is_rvalue_constant_expression
happens from cp_parser_constant_expression with 'allow_non_constant' != 0
and with 'non_constant_p' being a dummy out argument that comes from
cp_parser_functional_cast, so the result of is_rvalue_constant_expression
is effectively unused in this case, and we should be able to safely elide
it when 'allow_non_constant && non_constant_p == nullptr'.

Relatedly, ISTM the member cp_parser::non_integral_constant_expression_p
is also effectively unused and could be removed?

> 
> -- >8 --
> 
> is_really_empty_class is liable to crash when it gets an incomplete
> or dependent type.  Since r11-557, we pass the yet-uninstantiated
> class type S<0> of the PARM_DECL s to is_really_empty_class -- because
> of the potential_rvalue_constant_expression -> is_rvalue_constant_expression
> change in cp_parser_constant_expression.  Here we're not parsing
> a template so we did not check COMPLETE_TYPE_P as we should.
> 
>   PR c++/110106
> 
> gcc/cp/ChangeLog:
> 
>   * constexpr.cc (potential_constant_expression_1): Check COMPLETE_TYPE_P
>   even when !processing_template_decl.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp0x/noexcept80.C: New test.
> ---
>  gcc/cp/constexpr.cc |  2 +-
>  gcc/testsuite/g++.dg/cpp0x/noexcept80.C | 12 
>  2 files changed, 13 insertions(+), 1 deletion(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp0x/noexcept80.C
> 
> diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> index 6e8f1c2b61e..1f59c5472fb 100644
> --- a/gcc/cp/constexpr.cc
> +++ b/gcc/cp/constexpr.cc
> @@ -9116,7 +9116,7 @@ potential_constant_expression_1 (tree t, bool 
> want_rval, bool strict, bool now,
>if (now && want_rval)
>   {
> tree type = TREE_TYPE (t);
> -   if ((processing_template_decl && !COMPLETE_TYPE_P (type))
> +   if (!COMPLETE_TYPE_P (type)
> || dependent_type_p (type)
> || is_really_empty_class (type, /*ignore_vptr*/false))
>   /* An empty class has no data to read.  */
> diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept80.C 
> b/gcc/testsuite/g++.dg/cpp0x/noexcept80.C
> new file mode 100644
> index 000..3e90af747e2
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/noexcept80.C
> @@ -0,0 +1,12 @@
> +// PR c++/110106
> +// { dg-do compile { target c++11 } }
> +
> +template struct S
> +{
> +};
> +
> +struct G {
> +  G(S<0>);
> +};
> +
> +void y(S<0> s) noexcept(noexcept(G{s}));
> 
> base-commit: fca089e8a47314a40ad93527ba9f9d0d374b3afb
> -- 
> 2.41.0
> 
> 



[PATCH] c++: passing partially inst tmpl as ttp [PR110566]

2023-07-19 Thread Patrick Palka via Gcc-patches
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk/13?

-- >8 --

Since the arguments 'pargs' passed to the coerce_template_parms from
coerce_template_template_parms are always a full set, we need to make sure
we always pass the parameters of the most general template because if the
template is partially instantiated then the levels won't match up.  In the
testcase below during said call to coerce_template_parms the parameters
are {X, Y} both level 1, but the arguments are {{int}, {N, M}}, which
leads to a crash during auto deduction of X and Y.

PR c++/110566

gcc/cp/ChangeLog:

* pt.cc (coerce_template_template_parms): Simplify by using
DECL_INNERMOST_TEMPLATE_PARMS and removing redundant asserts.
Always pass the parameters of the most general template to
coerce_template_parms.

gcc/testsuite/ChangeLog:

* g++.dg/template/ttp38.C: New test.
---
 gcc/cp/pt.cc  | 12 +---
 gcc/testsuite/g++.dg/template/ttp38.C | 12 
 2 files changed, 17 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/ttp38.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index d882e9dd117..8723868823e 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -8073,12 +8073,10 @@ coerce_template_template_parms (tree parm_tmpl,
   tree parm, arg;
   int variadic_p = 0;
 
-  tree parm_parms = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (parm_tmpl));
-  tree arg_parms_full = DECL_TEMPLATE_PARMS (arg_tmpl);
-  tree arg_parms = INNERMOST_TEMPLATE_PARMS (arg_parms_full);
-
-  gcc_assert (TREE_CODE (parm_parms) == TREE_VEC);
-  gcc_assert (TREE_CODE (arg_parms) == TREE_VEC);
+  tree parm_parms = DECL_INNERMOST_TEMPLATE_PARMS (parm_tmpl);
+  tree arg_parms = DECL_INNERMOST_TEMPLATE_PARMS (arg_tmpl);
+  tree gen_arg_tmpl = most_general_template (arg_tmpl);
+  tree gen_arg_parms = DECL_INNERMOST_TEMPLATE_PARMS (gen_arg_tmpl);
 
   nparms = TREE_VEC_LENGTH (parm_parms);
   nargs = TREE_VEC_LENGTH (arg_parms);
@@ -8134,7 +8132,7 @@ coerce_template_template_parms (tree parm_tmpl,
scope_args = TI_ARGS (tinfo);
   pargs = add_to_template_args (scope_args, pargs);
 
-  pargs = coerce_template_parms (arg_parms, pargs, NULL_TREE, tf_none);
+  pargs = coerce_template_parms (gen_arg_parms, pargs, NULL_TREE, tf_none);
   if (pargs != error_mark_node)
{
  tree targs = make_tree_vec (nargs);
diff --git a/gcc/testsuite/g++.dg/template/ttp38.C 
b/gcc/testsuite/g++.dg/template/ttp38.C
new file mode 100644
index 000..7d25d291e81
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/ttp38.C
@@ -0,0 +1,12 @@
+// PR c++/110566
+// { dg-do compile { target c++20 } }
+
+template class>
+struct A;
+
+template
+struct B {
+  template struct C;
+};
+
+using type = A::C>;
-- 
2.41.0.376.gcba07a324d



Re: [PATCH] c++: passing partially inst tmpl as ttp [PR110566]

2023-07-19 Thread Patrick Palka via Gcc-patches
On Wed, Jul 19, 2023 at 2:05 PM Patrick Palka  wrote:
>
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk/13?
>
> -- >8 --
>
> Since the arguments 'pargs' passed to the coerce_template_parms from
> coerce_template_template_parms are always a full set, we need to make sure
> we always pass the parameters of the most general template because if the
> template is partially instantiated then the levels won't match up.  In the
> testcase below during said call to coerce_template_parms the parameters
> are {X, Y} both level 1, but the arguments are {{int}, {N, M}}, which
> leads to a crash during auto deduction of X and Y.
>
> PR c++/110566
>
> gcc/cp/ChangeLog:
>
> * pt.cc (coerce_template_template_parms): Simplify by using
> DECL_INNERMOST_TEMPLATE_PARMS and removing redundant asserts.
> Always pass the parameters of the most general template to
> coerce_template_parms.
>
> gcc/testsuite/ChangeLog:
>
> * g++.dg/template/ttp38.C: New test.
> ---
>  gcc/cp/pt.cc  | 12 +---
>  gcc/testsuite/g++.dg/template/ttp38.C | 12 
>  2 files changed, 17 insertions(+), 7 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/template/ttp38.C
>
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index d882e9dd117..8723868823e 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -8073,12 +8073,10 @@ coerce_template_template_parms (tree parm_tmpl,
>tree parm, arg;
>int variadic_p = 0;
>
> -  tree parm_parms = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS 
> (parm_tmpl));
> -  tree arg_parms_full = DECL_TEMPLATE_PARMS (arg_tmpl);
> -  tree arg_parms = INNERMOST_TEMPLATE_PARMS (arg_parms_full);
> -
> -  gcc_assert (TREE_CODE (parm_parms) == TREE_VEC);
> -  gcc_assert (TREE_CODE (arg_parms) == TREE_VEC);
> +  tree parm_parms = DECL_INNERMOST_TEMPLATE_PARMS (parm_tmpl);
> +  tree arg_parms = DECL_INNERMOST_TEMPLATE_PARMS (arg_tmpl);
> +  tree gen_arg_tmpl = most_general_template (arg_tmpl);
> +  tree gen_arg_parms = DECL_INNERMOST_TEMPLATE_PARMS (gen_arg_tmpl);
>
>nparms = TREE_VEC_LENGTH (parm_parms);
>nargs = TREE_VEC_LENGTH (arg_parms);
> @@ -8134,7 +8132,7 @@ coerce_template_template_parms (tree parm_tmpl,
> scope_args = TI_ARGS (tinfo);
>pargs = add_to_template_args (scope_args, pargs);
>
> -  pargs = coerce_template_parms (arg_parms, pargs, NULL_TREE, tf_none);
> +  pargs = coerce_template_parms (gen_arg_parms, pargs, NULL_TREE, 
> tf_none);
>if (pargs != error_mark_node)
> {
>   tree targs = make_tree_vec (nargs);
> diff --git a/gcc/testsuite/g++.dg/template/ttp38.C 
> b/gcc/testsuite/g++.dg/template/ttp38.C
> new file mode 100644
> index 000..7d25d291e81
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/template/ttp38.C
> @@ -0,0 +1,12 @@
> +// PR c++/110566
> +// { dg-do compile { target c++20 } }
> +
> +template class>
> +struct A;
> +
> +template
> +struct B {
> +  template struct C;

Oops, I botched a git commit --amend.  The parameter list here should
be 'auto X, auto Y'.

> +};
> +
> +using type = A::C>;
> --
> 2.41.0.376.gcba07a324d
>



Re: [PATCH] c++: fix ICE with designated initializer [PR110114]

2023-07-19 Thread Patrick Palka via Gcc-patches
On Wed, 19 Jul 2023, Marek Polacek wrote:

> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

LGTM.  It might be preferable to check COMPLETE_TYPE_P in the caller
instead, so that we avoid inspecting CLASSTYPE_NON_AGGREGATE on an
incomplete class type, and so that the caller doesn't "commit" to
building an aggregate conversion.

> 
> -- >8 --
> 
> r13-1227 added an assert checking that the index in a CONSTRUCTOR
> is a FIELD_DECL.  That's a reasonable assumption but in this case
> we never called reshape_init due to the type being incomplete, and
> so the index remained an identifier node: get_class_binding never
> got around to looking up the FIELD_DECL.
> 
> We can avoid the crash by returning early in build_aggr_conv; we'd
> return NULL anyway due to:
> 
>   if (i < CONSTRUCTOR_NELTS (ctor))
> return NULL;
> 
>   PR c++/110114
> 
> gcc/cp/ChangeLog:
> 
>   * call.cc (build_aggr_conv): Return early if the type isn't
>   complete.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp2a/desig28.C: New test.
>   * g++.dg/cpp2a/desig29.C: New test.
> ---
>  gcc/cp/call.cc   |  5 +
>  gcc/testsuite/g++.dg/cpp2a/desig28.C | 17 +
>  gcc/testsuite/g++.dg/cpp2a/desig29.C | 10 ++
>  3 files changed, 32 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/desig28.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/desig29.C
> 
> diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
> index b55230d98aa..0af20a81717 100644
> --- a/gcc/cp/call.cc
> +++ b/gcc/cp/call.cc
> @@ -986,6 +986,11 @@ build_aggr_conv (tree type, tree ctor, int flags, 
> tsubst_flags_t complain)
>tree empty_ctor = NULL_TREE;
>hash_set pset;
>  
> +  /* We've called complete_type on TYPE before calling this function, but
> + perhaps it wasn't successful.  */
> +  if (!COMPLETE_TYPE_P (type))
> +return nullptr;
> +
>/* We already called reshape_init in implicit_conversion, but it might not
>   have done anything in the case of parenthesized aggr init.  */
>  
> diff --git a/gcc/testsuite/g++.dg/cpp2a/desig28.C 
> b/gcc/testsuite/g++.dg/cpp2a/desig28.C
> new file mode 100644
> index 000..b63265fea51
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/desig28.C
> @@ -0,0 +1,17 @@
> +// PR c++/110114
> +// { dg-do compile { target c++20 } }
> +
> +struct A {
> +int a,b;
> +};
> +
> +struct B;
> +
> +void foo(const A &) {}
> +void foo(const B &) {}
> +
> +int
> +main ()
> +{
> +  foo({.a=0});
> +}
> diff --git a/gcc/testsuite/g++.dg/cpp2a/desig29.C 
> b/gcc/testsuite/g++.dg/cpp2a/desig29.C
> new file mode 100644
> index 000..bd1a82b041d
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/desig29.C
> @@ -0,0 +1,10 @@
> +// PR c++/110114
> +// { dg-do compile { target c++20 } }
> +
> +struct B;
> +
> +void foo(const B &) {}
> +
> +int main() {
> +foo({.a=0}); // { dg-error "invalid" }
> +}
> 
> base-commit: 2971ff7b1d564ac04b537d907c70e6093af70832
> -- 
> 2.41.0
> 
> 



Re: [PATCH] libstdc++: Define _GLIBCXX_HAS_BUILTIN_TRAIT

2023-07-19 Thread Patrick Palka via Gcc-patches
On Tue, 18 Jul 2023, Ken Matsui via Libstdc++ wrote:

> This patch defines _GLIBCXX_HAS_BUILTIN_TRAIT, which will be used as a
> flag to toggle built-in traits in the type_traits header. Through this
> macro function and _GLIBCXX_NO_BUILTIN_TRAITS macro, we can switch the
> use of built-in traits without needing to modify the source code.
> 
> libstdc++-v3/ChangeLog:
> 
>   * include/bits/c++config (_GLIBCXX_HAS_BUILTIN_TRAIT): Define.

The ChangeLog entry should also mention the change to _GLIBCXX_HAS_BUILTIN,
e.g.

(_GLIBCXX_HAS_BUILTIN): Keep defined.

> 
> Signed-off-by: Ken Matsui 
> ---
>  libstdc++-v3/include/bits/c++config | 6 +-
>  1 file changed, 5 insertions(+), 1 deletion(-)
> 
> diff --git a/libstdc++-v3/include/bits/c++config 
> b/libstdc++-v3/include/bits/c++config
> index dd47f274d5f..de13f61db71 100644
> --- a/libstdc++-v3/include/bits/c++config
> +++ b/libstdc++-v3/include/bits/c++config
> @@ -854,7 +854,11 @@ namespace __gnu_cxx
>  # define _GLIBCXX_HAVE_BUILTIN_LAUNDER 1
>  #endif
>  
> -#undef _GLIBCXX_HAS_BUILTIN
> +// Returns true if _GLIBCXX_NO_BUILTIN_TRAITS is not defined and the compiler
> +// has a corresponding built-in type trait. _GLIBCXX_NO_BUILTIN_TRAITS is
> +// defined to disable the use of built-in traits.
> +#define _GLIBCXX_HAS_BUILTIN_TRAIT(BT)  \
> +  (!defined(_GLIBCXX_NO_BUILTIN_TRAITS) && _GLIBCXX_HAS_BUILTIN(BT))

Since we don't expect _GLIBCXX_NO_BUILTIN_TRAITS to get
defined/undefined in the middle of preprocessing, perhaps we should
factor out the _GLIBCXX_NO_BUILTIN_TRAITS test from the macro function
and instead conditionally define the macro function to 0 according
_GLIBCXX_NO_BUILTIN_TRAITS?

>  
>  // Mark code that should be ignored by the compiler, but seen by Doxygen.
>  #define _GLIBCXX_DOXYGEN_ONLY(X)
> -- 
> 2.41.0
> 
> 



Re: [PATCH] c++: passing partially inst tmpl as ttp [PR110566]

2023-07-20 Thread Patrick Palka via Gcc-patches
On Wed, 19 Jul 2023, Jason Merrill wrote:

> On 7/19/23 14:05, Patrick Palka wrote:
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > trunk/13?
> > 
> > -- >8 --
> > 
> > Since the arguments 'pargs' passed to the coerce_template_parms from
> > coerce_template_template_parms are always a full set, we need to make sure
> > we always pass the parameters of the most general template because if the
> > template is partially instantiated then the levels won't match up.
> 
> Hmm, so then my comment "In that case we might end up adding more levels than
> needed, but that shouldn't be a problem; any args we need to refer to are at
> the right level." is wrong for auto template parms?

I suppose, but only for the ttp case I think?  It seems all is well when
passing an ordinary template as a ttp as long as we use the parameters of the
most general template for the coercion.  I can't come up with a counterexample
at least.

> 
> So I guess we likely need to do more to assure that pargs has the right number
> of levels if there are autos in the innermost arg parms.
> 
> Also, most_general_template doesn't work for TTPs, so that probably won't help
> handle their partial instantiations.

Ah, yeah :( Here's an analagous testcase that we still ICE on due to this:

  template class>
  struct A;

  template
  struct B {
template
struct C {
  template class TT>
  using type = A;
};
  };

  template struct B::C;

I think I have a fix using get_innermost_template_args.

> 
> And is it right for an alias template in a partial specialization?

IIUC yes, e.g. tsubst directly relies on most_general_template to work
for alias templates (when substituting an alias template specialization).

> 
> > In the
> > testcase below during said call to coerce_template_parms the parameters
> > are {X, Y} both level 1, but the arguments are {{int}, {N, M}}, which
> > leads to a crash during auto deduction of X and Y.
> > 
> > PR c++/110566
> 
> Since this is a regression from the patch for PR c++/108179, please list that
> PR here as well, to help avoid backporting that patch without this one.
> 
> > gcc/cp/ChangeLog:
> > 
> > * pt.cc (coerce_template_template_parms): Simplify by using
> > DECL_INNERMOST_TEMPLATE_PARMS and removing redundant asserts.
> > Always pass the parameters of the most general template to
> > coerce_template_parms.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/template/ttp38.C: New test.
> > ---
> >   gcc/cp/pt.cc  | 12 +---
> >   gcc/testsuite/g++.dg/template/ttp38.C | 12 
> >   2 files changed, 17 insertions(+), 7 deletions(-)
> >   create mode 100644 gcc/testsuite/g++.dg/template/ttp38.C
> > 
> > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > index d882e9dd117..8723868823e 100644
> > --- a/gcc/cp/pt.cc
> > +++ b/gcc/cp/pt.cc
> > @@ -8073,12 +8073,10 @@ coerce_template_template_parms (tree parm_tmpl,
> > tree parm, arg;
> > int variadic_p = 0;
> >   -  tree parm_parms = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS
> > (parm_tmpl));
> > -  tree arg_parms_full = DECL_TEMPLATE_PARMS (arg_tmpl);
> > -  tree arg_parms = INNERMOST_TEMPLATE_PARMS (arg_parms_full);
> > -
> > -  gcc_assert (TREE_CODE (parm_parms) == TREE_VEC);
> > -  gcc_assert (TREE_CODE (arg_parms) == TREE_VEC);
> > +  tree parm_parms = DECL_INNERMOST_TEMPLATE_PARMS (parm_tmpl);
> > +  tree arg_parms = DECL_INNERMOST_TEMPLATE_PARMS (arg_tmpl);
> > +  tree gen_arg_tmpl = most_general_template (arg_tmpl);
> > +  tree gen_arg_parms = DECL_INNERMOST_TEMPLATE_PARMS (gen_arg_tmpl);
> >   nparms = TREE_VEC_LENGTH (parm_parms);
> > nargs = TREE_VEC_LENGTH (arg_parms);
> > @@ -8134,7 +8132,7 @@ coerce_template_template_parms (tree parm_tmpl,
> > scope_args = TI_ARGS (tinfo);
> > pargs = add_to_template_args (scope_args, pargs);
> >   -  pargs = coerce_template_parms (arg_parms, pargs, NULL_TREE,
> > tf_none);
> > +  pargs = coerce_template_parms (gen_arg_parms, pargs, NULL_TREE,
> > tf_none);
> > if (pargs != error_mark_node)
> > {
> >   tree targs = make_tree_vec (nargs);
> > diff --git a/gcc/testsuite/g++.dg/template/ttp38.C
> > b/gcc/testsuite/g++.dg/template/ttp38.C
> > new file mode 100644
> > index 000..7d25d291e81
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/template/ttp38.C
> > @@ -0,0 +1,12 @@
> > +// PR c++/110566
> > +// { dg-do compile { target c++20 } }
> > +
> > +template class>
> > +struct A;
> > +
> > +template
> > +struct B {
> > +  template struct C;
> > +};
> > +
> > +using type = A::C>;
> 
> 



Re: [PATCH v2] libstdc++: Define _GLIBCXX_HAS_BUILTIN_TRAIT

2023-07-20 Thread Patrick Palka via Gcc-patches
On Wed, Jul 19, 2023 at 3:33 PM Ken Matsui via Gcc-patches
 wrote:
>
> This patch defines _GLIBCXX_HAS_BUILTIN_TRAIT macro, which will be used
> as a flag to toggle the use of built-in traits in the type_traits header
> through _GLIBCXX_NO_BUILTIN_TRAITS macro, without needing to modify the
> source code.

LGTM!

>
> libstdc++-v3/ChangeLog:
>
> * include/bits/c++config (_GLIBCXX_HAS_BUILTIN_TRAIT): Define.
> (_GLIBCXX_HAS_BUILTIN): Keep defined.
>
> Signed-off-by: Ken Matsui 
> ---
>  libstdc++-v3/include/bits/c++config | 10 +-
>  1 file changed, 9 insertions(+), 1 deletion(-)
>
> diff --git a/libstdc++-v3/include/bits/c++config 
> b/libstdc++-v3/include/bits/c++config
> index dd47f274d5f..984985d6fff 100644
> --- a/libstdc++-v3/include/bits/c++config
> +++ b/libstdc++-v3/include/bits/c++config
> @@ -854,7 +854,15 @@ namespace __gnu_cxx
>  # define _GLIBCXX_HAVE_BUILTIN_LAUNDER 1
>  #endif
>
> -#undef _GLIBCXX_HAS_BUILTIN
> +// Returns 1 if _GLIBCXX_NO_BUILTIN_TRAITS is not defined and the compiler
> +// has a corresponding built-in type trait, 0 otherwise.
> +// _GLIBCXX_NO_BUILTIN_TRAITS can be defined to disable the use of built-in
> +// traits.
> +#ifndef _GLIBCXX_NO_BUILTIN_TRAITS
> +# define _GLIBCXX_HAS_BUILTIN_TRAIT(BT) _GLIBCXX_HAS_BUILTIN(BT)
> +#else
> +# define _GLIBCXX_HAS_BUILTIN_TRAIT(BT) 0
> +#endif
>
>  // Mark code that should be ignored by the compiler, but seen by Doxygen.
>  #define _GLIBCXX_DOXYGEN_ONLY(X)
> --
> 2.41.0
>



[PATCH 2/1] c++: passing partially inst ttp as ttp [PR110566]

2023-07-21 Thread Patrick Palka via Gcc-patches
(This is a follow-up of
https://gcc.gnu.org/pipermail/gcc-patches/2023-July/624951.html)

Bootstrapped and regtested on x86_64-pc-linux-gnu, how does this look?

-- >8 --

The previous fix doesn't work for partially instantiated ttps primarily
because most_general_template doesn't work for them.  This patch fixes
this by giving such ttps a DECL_TEMPLATE_INFO (extending the
r11-734-g2fb595f8348e16 fix) with which we can obtain the original ttp.

This patch additionally makes us be more careful about using the correct
amount of levels from the scope of a ttp argument during
coerce_template_template_parms.

PR c++/110566

gcc/cp/ChangeLog:

* pt.cc (reduce_template_parm_level): Set DECL_TEMPLATE_INFO
on the DECL_TEMPLATE_RESULT of a reduced template template
parameter.
(add_defaults_to_ttp): Also update DECL_TEMPLATE_INFO of the
ttp's DECL_TEMPLATE_RESULT.
(coerce_template_template_parms): Make sure 'scope_args' has
the right amount of levels for the ttp argument.
(most_general_template): Handle template template parameters.

gcc/testsuite/ChangeLog:

* g++.dg/template/ttp39.C: New test.
---
 gcc/cp/pt.cc  | 46 ---
 gcc/testsuite/g++.dg/template/ttp39.C | 16 ++
 2 files changed, 57 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/ttp39.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index e0ed4bc8bbb..be7119dd9a0 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -4570,8 +4570,14 @@ reduce_template_parm_level (tree index, tree type, int 
levels, tree args,
  TYPE_DECL, DECL_NAME (decl), type);
  DECL_TEMPLATE_RESULT (decl) = inner;
  DECL_ARTIFICIAL (inner) = true;
- DECL_TEMPLATE_PARMS (decl) = tsubst_template_parms
-   (DECL_TEMPLATE_PARMS (orig_decl), args, complain);
+ tree parms = tsubst_template_parms (DECL_TEMPLATE_PARMS (orig_decl),
+ args, complain);
+ DECL_TEMPLATE_PARMS (decl) = parms;
+ retrofit_lang_decl (inner);
+ tree orig_inner = DECL_TEMPLATE_RESULT (orig_decl);
+ DECL_TEMPLATE_INFO (inner)
+   = build_template_info (DECL_TI_TEMPLATE (orig_inner),
+  template_parms_to_args (parms));
}
 
   /* Attach the TPI to the decl.  */
@@ -7936,6 +7942,19 @@ add_defaults_to_ttp (tree otmpl)
}
 }
 
+  tree oresult = DECL_TEMPLATE_RESULT (otmpl);
+  tree gen_otmpl = DECL_TI_TEMPLATE (oresult);
+  tree gen_ntmpl;
+  if (gen_otmpl == otmpl)
+gen_ntmpl = ntmpl;
+  else
+gen_ntmpl = add_defaults_to_ttp (gen_otmpl);
+
+  tree nresult = copy_node (oresult);
+  DECL_TEMPLATE_INFO (nresult) = copy_node (DECL_TEMPLATE_INFO (oresult));
+  DECL_TI_TEMPLATE (nresult) = gen_ntmpl;
+  DECL_TEMPLATE_RESULT (ntmpl) = nresult;
+
   hash_map_safe_put (defaulted_ttp_cache, otmpl, ntmpl);
   return ntmpl;
 }
@@ -8121,15 +8140,29 @@ coerce_template_template_parms (tree parm_tmpl,
 OUTER_ARGS are not the right outer levels in this case, as they are
 the args we're building up for PARM, and for the coercion we want the
 args for ARG.  If DECL_CONTEXT isn't set for a template template
-parameter, we can assume that it's in the current scope.  In that case
-we might end up adding more levels than needed, but that shouldn't be
-a problem; any args we need to refer to are at the right level.  */
+parameter, we can assume that it's in the current scope.  */
   tree ctx = DECL_CONTEXT (arg_tmpl);
   if (!ctx && DECL_TEMPLATE_TEMPLATE_PARM_P (arg_tmpl))
ctx = current_scope ();
   tree scope_args = NULL_TREE;
   if (tree tinfo = get_template_info (ctx))
scope_args = TI_ARGS (tinfo);
+  if (DECL_TEMPLATE_TEMPLATE_PARM_P (arg_tmpl))
+   {
+ int level = TEMPLATE_TYPE_LEVEL (TREE_TYPE (gen_arg_tmpl));
+ int scope_depth = TMPL_ARGS_DEPTH (scope_args);
+ if (scope_depth >= level)
+   /* Only use as many levels from the scope as needed (not
+  including the level of ARG).  */
+   scope_args = strip_innermost_template_args
+ (scope_args, scope_depth - (level - 1));
+
+ /* Add the arguments that appear at the level of ARG.  */
+ tree adj_args = DECL_TI_ARGS (DECL_TEMPLATE_RESULT (arg_tmpl));
+ adj_args = TMPL_ARGS_LEVEL (adj_args, TMPL_ARGS_DEPTH (adj_args) - 1);
+ scope_args = add_to_template_args (scope_args, adj_args);
+   }
+
   pargs = add_to_template_args (scope_args, pargs);
 
   pargs = coerce_template_parms (gen_arg_parms, pargs, NULL_TREE, tf_none);
@@ -25985,6 +26018,9 @@ most_general_template (tree decl)
return NULL_TREE;
 }
 
+  if (DECL_TEMPLATE_TEMPLATE_PARM_P (decl))
+return DECL_TI_TEMPLATE (DECL_TEMPLATE_RESULT (decl));
+
   /* Look for more a

Re: [PATCH] testsuite: Adjust g++.dg/gomp/pr58567.C to new compiler message

2023-07-24 Thread Patrick Palka via Gcc-patches
On Fri, Jul 21, 2023 at 5:29 PM Thiago Jung Bauermann
 wrote:
>
> Commit 92d1425ca780 "c++: redundant targ coercion for var/alias tmpls"
> changed the compiler error message in this testcase from
>
> : In instantiation of 'void foo() [with T = int]':
> :14:11:   required from here
> :8:22: error: 'int' is not a class, struct, or union type
> :8:22: error: 'int' is not a class, struct, or union type
> :8:22: error: 'int' is not a class, struct, or union type
> :8:3: error: expected iteration declaration or initialization
> compiler exited with status 1
>
> to:
>
> : In instantiation of 'void foo() [with T = int]':
> :14:11:   required from here
> :8:22: error: 'int' is not a class, struct, or union type
> :8:3: error: invalid type for iteration variable 'i'
> compiler exited with status 1
> Excess errors:
> :8:3: error: invalid type for iteration variable 'i'
>
> Andrew Pinski analysed the issue in PR 110756 and considered that it was a
> testsuite issue in that the error message changed slightly.  Also, it's a
> better error message.
>
> Therefore, we only need to adjust the testcase to expect the new message.

Thanks! I can't approve this patch but it looks good to me.


>
> gcc/testsuite/ChangeLog:
> PR testsuite/110756
> g++.dg/gomp/pr58567.C: Adjust to new compiler error message.
> ---
>  gcc/testsuite/g++.dg/gomp/pr58567.C | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/gcc/testsuite/g++.dg/gomp/pr58567.C 
> b/gcc/testsuite/g++.dg/gomp/pr58567.C
> index 35a5bb027ffe..866d831c65e4 100644
> --- a/gcc/testsuite/g++.dg/gomp/pr58567.C
> +++ b/gcc/testsuite/g++.dg/gomp/pr58567.C
> @@ -5,7 +5,7 @@
>  template void foo()
>  {
>#pragma omp parallel for
> -  for (typename T::X i = 0; i < 100; ++i)  /* { dg-error "'int' is not a 
> class, struct, or union type|expected iteration declaration or 
> initialization" } */
> +  for (typename T::X i = 0; i < 100; ++i)  /* { dg-error "'int' is not a 
> class, struct, or union type|invalid type for iteration variable 'i'" } */
>  ;
>  }
>
>



Re: [PATCH 2/1] c++: passing partially inst ttp as ttp [PR110566]

2023-07-24 Thread Patrick Palka via Gcc-patches
On Fri, 21 Jul 2023, Jason Merrill wrote:

> On 7/21/23 14:34, Patrick Palka wrote:
> > (This is a follow-up of
> > https://gcc.gnu.org/pipermail/gcc-patches/2023-July/624951.html)
> > 
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, how does this look?
> > 
> > -- >8 --
> > 
> > The previous fix doesn't work for partially instantiated ttps primarily
> > because most_general_template doesn't work for them.  This patch fixes
> > this by giving such ttps a DECL_TEMPLATE_INFO (extending the
> > r11-734-g2fb595f8348e16 fix) with which we can obtain the original ttp.
> > 
> > This patch additionally makes us be more careful about using the correct
> > amount of levels from the scope of a ttp argument during
> > coerce_template_template_parms.
> > 
> > PR c++/110566
> > 
> > gcc/cp/ChangeLog:
> > 
> > * pt.cc (reduce_template_parm_level): Set DECL_TEMPLATE_INFO
> > on the DECL_TEMPLATE_RESULT of a reduced template template
> > parameter.
> > (add_defaults_to_ttp): Also update DECL_TEMPLATE_INFO of the
> > ttp's DECL_TEMPLATE_RESULT.
> > (coerce_template_template_parms): Make sure 'scope_args' has
> > the right amount of levels for the ttp argument.
> > (most_general_template): Handle template template parameters.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/template/ttp39.C: New test.
> > ---
> >   gcc/cp/pt.cc  | 46 ---
> >   gcc/testsuite/g++.dg/template/ttp39.C | 16 ++
> >   2 files changed, 57 insertions(+), 5 deletions(-)
> >   create mode 100644 gcc/testsuite/g++.dg/template/ttp39.C
> > 
> > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > index e0ed4bc8bbb..be7119dd9a0 100644
> > --- a/gcc/cp/pt.cc
> > +++ b/gcc/cp/pt.cc
> > @@ -4570,8 +4570,14 @@ reduce_template_parm_level (tree index, tree type,
> > int levels, tree args,
> >   TYPE_DECL, DECL_NAME (decl), type);
> >   DECL_TEMPLATE_RESULT (decl) = inner;
> >   DECL_ARTIFICIAL (inner) = true;
> > - DECL_TEMPLATE_PARMS (decl) = tsubst_template_parms
> > -   (DECL_TEMPLATE_PARMS (orig_decl), args, complain);
> > + tree parms = tsubst_template_parms (DECL_TEMPLATE_PARMS (orig_decl),
> > + args, complain);
> > + DECL_TEMPLATE_PARMS (decl) = parms;
> > + retrofit_lang_decl (inner);
> > + tree orig_inner = DECL_TEMPLATE_RESULT (orig_decl);
> > + DECL_TEMPLATE_INFO (inner)
> > +   = build_template_info (DECL_TI_TEMPLATE (orig_inner),
> > +  template_parms_to_args (parms));
> 
> Should we assert that orig_inner doesn't have its own DECL_TEMPLATE_INFO?  I'm
> wondering if it's possible to reduce the level of a TTP more than once.

It's possible for a ttp belonging to a nested generic lambda:

  template
  void f() {
[](auto) {
  [] class TT>() {
  };
}(0);
  }

  template void f();

> 
> > }
> >   /* Attach the TPI to the decl.  */
> > @@ -7936,6 +7942,19 @@ add_defaults_to_ttp (tree otmpl)
> > }
> >   }
> >   +  tree oresult = DECL_TEMPLATE_RESULT (otmpl);
> > +  tree gen_otmpl = DECL_TI_TEMPLATE (oresult);
> 
> Hmm, here we're assuming that all TTPs have DECL_TEMPLATE_INFO?

I figured it's a reasonable assumption since all "formal" ttps
originally start out with DECL_TEMPLATE_INFO (via process_template_parm).
Though I realized I missed adjusting rewrite_template_parm to set
DECL_TEMPLATE_INFO on the new ttp, which the below patch fixes (and
adds a testcase that we'd otherwise segfualt on).

> 
> > +  tree gen_ntmpl;
> > +  if (gen_otmpl == otmpl)
> > +gen_ntmpl = ntmpl;
> > +  else
> > +gen_ntmpl = add_defaults_to_ttp (gen_otmpl);
> > +
> > +  tree nresult = copy_node (oresult);

Another fixed bug: since we build the new DECL_TEMPLATE_RESULT via
copy_node, we need to avoid sharing its DECL_LANG_SPECIFIC with the
old decl.

> > +  DECL_TEMPLATE_INFO (nresult) = copy_node (DECL_TEMPLATE_INFO (oresult));
> > +  DECL_TI_TEMPLATE (nresult) = gen_ntmpl;
> > +  DECL_TEMPLATE_RESULT (ntmpl) = nresult;
> > +
> > hash_map_safe_put (defaulted_ttp_cache, otmpl, ntmpl);
> > return ntmpl;
> >   }
> > @@ -8121,15 +8140,29 @@ coerce_template_template_parms (tree parm_tmpl,
> >  OUTER_ARGS are not the right outer levels in this case, as they are
> >  the args we're building up for PARM, and for the coercion we want the
> >  args for ARG.  If DECL_CONTEXT isn't set for a template template
> > -parameter, we can assume that it's in the current scope.  In that
> > case
> > -we might end up adding more levels than needed, but that shouldn't be
> > -a problem; any args we need to refer to are at the right level.  */
> > +parameter, we can assume that it's in the current scope.  */
> > tree ctx = DECL_CONTEXT (arg_tmpl);
> > if (!ctx && DECL_TEMPLATE_TEMPLATE_PARM_P (arg_tmpl))
> > ctx = current_scope ();
> > tree scope_args = NULL_TREE;
> >  

[PATCH] c++: unifying REAL_CSTs [PR110809]

2023-07-26 Thread Patrick Palka via Gcc-patches
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk/13 (after the branch is unfrozen)?

-- >8 --

This teaches unify how to compare two REAL_CSTs.

PR c++/110809

gcc/cp/ChangeLog:

* pt.cc (unify) : Generalize to handle
REAL_CST as well.

gcc/testsuite/ChangeLog:

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

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index d342ab5929a..1e09f304490 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -24890,12 +24890,13 @@ unify (tree tparms, tree targs, tree parm, tree arg, 
int strict,
   /* Types INTEGER_CST and MINUS_EXPR can come from array bounds.  */
   /* Type INTEGER_CST can come from ordinary constant template args.  */
 case INTEGER_CST:
+case REAL_CST:
   while (CONVERT_EXPR_P (arg))
arg = TREE_OPERAND (arg, 0);
 
-  if (TREE_CODE (arg) != INTEGER_CST)
+  if (TREE_CODE (arg) != TREE_CODE (parm))
return unify_template_argument_mismatch (explain_p, parm, arg);
-  return (tree_int_cst_equal (parm, arg)
+  return (simple_cst_equal (parm, arg)
  ? unify_success (explain_p)
  : unify_template_argument_mismatch (explain_p, parm, arg));
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-float3.C 
b/gcc/testsuite/g++.dg/cpp2a/nontype-float3.C
new file mode 100644
index 000..044fb99905a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nontype-float3.C
@@ -0,0 +1,12 @@
+// PR c++/110809
+// { dg-do compile { target c++20 } }
+
+template struct A { };
+
+template void f(A);
+template void f(A);
+
+int main() {
+  f(A{});
+  f(A{}); // { dg-error "no match" }
+}
-- 
2.41.0.450.ga80be15292



[PATCH] c++: constexpr empty subobject confusion [PR110197]

2023-07-26 Thread Patrick Palka via Gcc-patches
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk/13 (later)?

-- >8 --

Now that init_subob_ctx no longer sets new_ctx.ctor for a subobject of
empty type, it seems we need to ensure its callers cxx_eval_bare_aggregate
and cxx_eval_vec_init_1 consistently omit entries for such subobjects in
the parent ctx->ctor.  We also need to allow cxx_eval_array_reference
to synthesize an empty element object even if the array CONSTRUCTOR
has CONSTRUCTOR_NO_CLEARING set.

PR c++/110197

gcc/cp/ChangeLog:

* constexpr.cc (cxx_eval_array_reference): Return a synthesized
empty subobject even if CONSTRUCTOR_NO_CLEARING is set.
(cxx_eval_bare_aggregate): Set 'no_slot' to true more generally
whenever new_ctx.ctor is empty, i.e. for any subobject of empty
type.
(cxx_eval_vec_init_1): Define 'no_slot' as above and use it
accordingly.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/constexpr-empty18.C: New test.
* g++.dg/cpp0x/constexpr-empty19.C: New test.
---
 gcc/cp/constexpr.cc   | 23 +--
 .../g++.dg/cpp0x/constexpr-empty18.C  |  7 ++
 .../g++.dg/cpp0x/constexpr-empty19.C  | 12 ++
 3 files changed, 35 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-empty18.C
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-empty19.C

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index f2fcb54626d..da2c3116810 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -4297,6 +4297,9 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree 
t,
 
   /* Not found.  */
 
+  if (is_really_empty_class (elem_type, /*ignore_vptr*/false))
+return build_constructor (elem_type, NULL);
+
   if (TREE_CODE (ary) == CONSTRUCTOR
   && CONSTRUCTOR_NO_CLEARING (ary))
 {
@@ -4314,9 +4317,7 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree 
t,
  directly for non-aggregates to avoid creating a garbage CONSTRUCTOR.  */
   tree val;
   constexpr_ctx new_ctx;
-  if (is_really_empty_class (elem_type, /*ignore_vptr*/false))
-return build_constructor (elem_type, NULL);
-  else if (CP_AGGREGATE_TYPE_P (elem_type))
+  if (CP_AGGREGATE_TYPE_P (elem_type))
 {
   tree empty_ctor = build_constructor (init_list_type_node, NULL);
   val = digest_init (elem_type, empty_ctor, tf_warning_or_error);
@@ -5095,9 +5096,9 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t,
   FOR_EACH_CONSTRUCTOR_ELT (v, i, index, value)
 {
   tree orig_value = value;
-  /* Like in cxx_eval_store_expression, omit entries for empty fields.  */
-  bool no_slot = TREE_CODE (type) == RECORD_TYPE && is_empty_field (index);
   init_subob_ctx (ctx, new_ctx, index, value);
+  /* Like in cxx_eval_store_expression, omit entries for empty fields.  */
+  bool no_slot = new_ctx.ctor == NULL_TREE;
   int pos_hint = -1;
   if (new_ctx.ctor != ctx->ctor && !no_slot)
{
@@ -5261,7 +5262,8 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree 
atype, tree init,
   bool reuse = false;
   constexpr_ctx new_ctx;
   init_subob_ctx (ctx, new_ctx, idx, pre_init ? init : elttype);
-  if (new_ctx.ctor != ctx->ctor)
+  bool no_slot = new_ctx.ctor == NULL_TREE;
+  if (new_ctx.ctor != ctx->ctor && !no_slot)
{
  if (zeroed_out)
CONSTRUCTOR_NO_CLEARING (new_ctx.ctor) = false;
@@ -5306,7 +5308,14 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree 
atype, tree init,
}
   if (*non_constant_p)
break;
-  if (new_ctx.ctor != ctx->ctor)
+  if (no_slot)
+   {
+ /* This is an initializer for an empty subobject; now that we've
+checked that it's constant, we can ignore it.  */
+ gcc_checking_assert (i == 0);
+ break;
+   }
+  else if (new_ctx.ctor != ctx->ctor)
{
  /* We appended this element above; update the value.  */
  gcc_assert ((*p)->last().index == idx);
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-empty18.C 
b/gcc/testsuite/g++.dg/cpp0x/constexpr-empty18.C
new file mode 100644
index 000..4bb9e3dcb64
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-empty18.C
@@ -0,0 +1,7 @@
+// PR c++/110197
+// { dg-do compile { target c++11 } }
+
+struct A { constexpr A(int) { } };
+struct B { A a; };
+constexpr B f(int n) { return B{A{n}}; }
+constexpr B b = f(1);
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-empty19.C 
b/gcc/testsuite/g++.dg/cpp0x/constexpr-empty19.C
new file mode 100644
index 000..5ad67682c5b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-empty19.C
@@ -0,0 +1,12 @@
+// PR c++/110197
+// { dg-do compile { target c++11 } }
+
+struct A {
+  constexpr A() : A(__builtin_is_constant_evaluated()) { }
+  constexpr A(int) { }
+};
+constexpr A a1[1] = {{}};
+constexpr A a2[2] = {{}, {}};
+constexpr A a3[3] = {{}, {}, {

[PATCH] tree-pretty-print: handle COMPONENT_REF with non-decl RHS

2023-07-31 Thread Patrick Palka via Gcc-patches
Tested on x86_64-pc-linux-gnu, does this look OK for trunk?

-- >8 --

In the C++ front end, a COMPONENT_REF's second operand isn't always a
decl (at least at template parse time).  This patch makes the generic
pretty printer not ICE when printing such a COMPONENT_REF.

gcc/ChangeLog:

* tree-pretty-print.cc (dump_generic_node) :
Don't call component_ref_field_offset if the RHS isn't a decl.
---
 gcc/tree-pretty-print.cc | 16 +---
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/gcc/tree-pretty-print.cc b/gcc/tree-pretty-print.cc
index 25d191b10fd..da8dd002a3b 100644
--- a/gcc/tree-pretty-print.cc
+++ b/gcc/tree-pretty-print.cc
@@ -2482,14 +2482,16 @@ dump_generic_node (pretty_printer *pp, tree node, int 
spc, dump_flags_t flags,
   if (op_prio (op0) < op_prio (node))
pp_right_paren (pp);
   pp_string (pp, str);
-  dump_generic_node (pp, TREE_OPERAND (node, 1), spc, flags, false);
-  op0 = component_ref_field_offset (node);
-  if (op0 && TREE_CODE (op0) != INTEGER_CST)
-   {
- pp_string (pp, "{off: ");
- dump_generic_node (pp, op0, spc, flags, false);
+  op1 = TREE_OPERAND (node, 1);
+  dump_generic_node (pp, op1, spc, flags, false);
+  if (DECL_P (op1))
+   if (tree off = component_ref_field_offset (node))
+ if (TREE_CODE (off) != INTEGER_CST)
+   {
+ pp_string (pp, "{off: ");
+ dump_generic_node (pp, off, spc, flags, false);
  pp_right_brace (pp);
-   }
+   }
   break;
 
 case BIT_FIELD_REF:
-- 
2.41.0.478.gee48e70a82



[PATCH] c++: improve debug_tree for templated types/decls

2023-07-31 Thread Patrick Palka via Gcc-patches
Tested on x86_64-pc-linux-gnu, does this look OK for trunk?

-- >8 --

gcc/cp/ChangeLog:

* ptree.cc (cxx_print_decl): Check for DECL_LANG_SPECIFIC and
TS_DECL_COMMON only when necessary.  Print DECL_TEMPLATE_INFO
for all decls that have it, not just VAR_DECL or FUNCTION_DECL.
Also print DECL_USE_TEMPLATE.
(cxx_print_type): Print TYPE_TEMPLATE_INFO.
: Don't print TYPE_TI_ARGS
anymore.
: Print TEMPLATE_TYPE_PARM_INDEX
instead of printing the index, level and original level
individually.
---
 gcc/cp/ptree.cc | 32 +---
 1 file changed, 17 insertions(+), 15 deletions(-)

diff --git a/gcc/cp/ptree.cc b/gcc/cp/ptree.cc
index 33af7b81f58..13306fc8762 100644
--- a/gcc/cp/ptree.cc
+++ b/gcc/cp/ptree.cc
@@ -38,10 +38,6 @@ cxx_print_decl (FILE *file, tree node, int indent)
   return;
 }
 
-  if (!CODE_CONTAINS_STRUCT (TREE_CODE (node), TS_DECL_COMMON)
-  || !DECL_LANG_SPECIFIC (node))
-return;
-
   if (TREE_CODE (node) == FUNCTION_DECL)
 {
   int flags = TFF_DECL_SPECIFIERS|TFF_RETURN_TYPE
@@ -106,7 +102,10 @@ cxx_print_decl (FILE *file, tree node, int indent)
   need_indent = false;
 }
 
-  if (DECL_EXTERNAL (node) && DECL_NOT_REALLY_EXTERN (node))
+  if (CODE_CONTAINS_STRUCT (TREE_CODE (node), TS_DECL_COMMON)
+  && DECL_LANG_SPECIFIC (node)
+  && DECL_EXTERNAL (node)
+  && DECL_NOT_REALLY_EXTERN (node))
 {
   if (need_indent)
indent_to (file, indent + 3);
@@ -115,6 +114,7 @@ cxx_print_decl (FILE *file, tree node, int indent)
 }
 
   if (TREE_CODE (node) == FUNCTION_DECL
+  && DECL_LANG_SPECIFIC (node)
   && DECL_PENDING_INLINE_INFO (node))
 {
   if (need_indent)
@@ -124,27 +124,29 @@ cxx_print_decl (FILE *file, tree node, int indent)
   need_indent = false;
 }
   
-  if (VAR_OR_FUNCTION_DECL_P (node)
+  if (DECL_LANG_SPECIFIC (node)
   && DECL_TEMPLATE_INFO (node))
-print_node (file, "template-info", DECL_TEMPLATE_INFO (node),
-   indent + 4);
+{
+  print_node (file, "template-info", DECL_TEMPLATE_INFO (node),
+ indent + 4);
+  indent_to (file, indent + 3);
+  fprintf (file, " use_template=%d", DECL_USE_TEMPLATE (node));
+}
 }
 
 void
 cxx_print_type (FILE *file, tree node, int indent)
 {
+  if (TYPE_LANG_SPECIFIC (node)
+  && TYPE_TEMPLATE_INFO (node))
+print_node (file, "template-info", TYPE_TEMPLATE_INFO (node), indent + 4);
+
   switch (TREE_CODE (node))
 {
 case BOUND_TEMPLATE_TEMPLATE_PARM:
-  print_node (file, "args", TYPE_TI_ARGS (node), indent + 4);
-  gcc_fallthrough ();
-
 case TEMPLATE_TYPE_PARM:
 case TEMPLATE_TEMPLATE_PARM:
-  indent_to (file, indent + 3);
-  fprintf (file, "index %d level %d orig_level %d",
-  TEMPLATE_TYPE_IDX (node), TEMPLATE_TYPE_LEVEL (node),
-  TEMPLATE_TYPE_ORIG_LEVEL (node));
+  print_node (file, "tpi", TEMPLATE_TYPE_PARM_INDEX (node), indent + 4);
   return;
 
 case FUNCTION_TYPE:
-- 
2.41.0.478.gee48e70a82



Re: [PATCH v3 2/2] libstdc++: Use _GLIBCXX_HAS_BUILTIN_TRAIT

2023-08-01 Thread Patrick Palka via Gcc-patches
On Thu, 27 Jul 2023, Ken Matsui via Gcc-patches wrote:

> This patch uses _GLIBCXX_HAS_BUILTIN_TRAIT macro instead of
> __has_builtin in the type_traits header. This macro supports to toggle
> the use of built-in traits in the type_traits header through
> _GLIBCXX_NO_BUILTIN_TRAITS macro, without needing to modify the
> source code.
> 
> libstdc++-v3/ChangeLog:
> 
>   * include/std/type_traits (__has_builtin): Replace with ...
>   (_GLIBCXX_HAS_BUILTIN): ... this.
> 
> Signed-off-by: Ken Matsui 
> ---
>  libstdc++-v3/include/std/type_traits | 26 +-
>  1 file changed, 13 insertions(+), 13 deletions(-)
> 
> diff --git a/libstdc++-v3/include/std/type_traits 
> b/libstdc++-v3/include/std/type_traits
> index 9f086992ebc..12423361b6e 100644
> --- a/libstdc++-v3/include/std/type_traits
> +++ b/libstdc++-v3/include/std/type_traits
> @@ -1411,7 +1411,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>  : public __bool_constant<__is_base_of(_Base, _Derived)>
>  { };
>  
> -#if __has_builtin(__is_convertible)
> +#if _GLIBCXX_HAS_BUILTIN_TRAIT(__is_convertible)
>template
>  struct is_convertible
>  : public __bool_constant<__is_convertible(_From, _To)>
> @@ -1462,7 +1462,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>  #if __cplusplus >= 202002L
>  #define __cpp_lib_is_nothrow_convertible 201806L
>  
> -#if __has_builtin(__is_nothrow_convertible)
> +#if _GLIBCXX_HAS_BUILTIN_TRAIT(__is_nothrow_convertible)
>/// is_nothrow_convertible_v
>template
>  inline constexpr bool is_nothrow_convertible_v
> @@ -1537,7 +1537,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>  { using type = _Tp; };
>  
>/// remove_cv
> -#if __has_builtin(__remove_cv)
> +#if _GLIBCXX_HAS_BUILTIN_TRAIT(__remove_cv)
>template
>  struct remove_cv
>  { using type = __remove_cv(_Tp); };
> @@ -1606,7 +1606,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>// Reference transformations.
>  
>/// remove_reference
> -#if __has_builtin(__remove_reference)
> +#if _GLIBCXX_HAS_BUILTIN_TRAIT(__remove_reference)
>template
>  struct remove_reference
>  { using type = __remove_reference(_Tp); };
> @@ -2963,7 +2963,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>template  bool _Nothrow = noexcept(_S_conv<_Tp>(_S_get())),
>  typename = decltype(_S_conv<_Tp>(_S_get())),
> -#if __has_builtin(__reference_converts_from_temporary)
> +#if _GLIBCXX_HAS_BUILTIN_TRAIT(__reference_converts_from_temporary)
>  bool _Dangle = __reference_converts_from_temporary(_Tp, _Res_t)
>  #else
>  bool _Dangle = false
> @@ -3420,7 +3420,7 @@ template
> */
>  #define __cpp_lib_remove_cvref 201711L
>  
> -#if __has_builtin(__remove_cvref)
> +#if _GLIBCXX_HAS_BUILTIN_TRAIT(__remove_cvref)
>template
>  struct remove_cvref
>  { using type = __remove_cvref(_Tp); };
> @@ -3515,7 +3515,7 @@ template
>  : public bool_constant>
>  { };
>  
> -#if __has_builtin(__is_layout_compatible)
> +#if _GLIBCXX_HAS_BUILTIN_TRAIT(__is_layout_compatible)

Hmm, I was thinking we'd use this macro only for traits that have a
fallback non-built-in implementation so that we could easily use/test
their fallback implementation.  For traits that don't have such a
fallback, using this macro would mean that trait would no longer get
defined at all, which doesn't seem as useful.  Perhaps let's initially
adjust only the traits that have a fallback implementation?

We could then verify that using the fallback implementation for all such
traits works as expected by running the testsuite with:

  make check RUNTESTFLAGS="conformance.exp 
--target_board=unix/-D_GLIBCXX_NO_BUILTIN_TRAITS"

>  
>/// @since C++20
>template
> @@ -3529,7 +3529,7 @@ template
>  constexpr bool is_layout_compatible_v
>= __is_layout_compatible(_Tp, _Up);
>  
> -#if __has_builtin(__builtin_is_corresponding_member)
> +#if _GLIBCXX_HAS_BUILTIN_TRAIT(__builtin_is_corresponding_member)
>  #define __cpp_lib_is_layout_compatible 201907L
>  
>/// @since C++20
> @@ -3540,7 +3540,7 @@ template
>  #endif
>  #endif
>  
> -#if __has_builtin(__is_pointer_interconvertible_base_of)
> +#if _GLIBCXX_HAS_BUILTIN_TRAIT(__is_pointer_interconvertible_base_of)
>/// True if `_Derived` is standard-layout and has a base class of type 
> `_Base`
>/// @since C++20
>template
> @@ -3554,7 +3554,7 @@ template
>  constexpr bool is_pointer_interconvertible_base_of_v
>= __is_pointer_interconvertible_base_of(_Base, _Derived);
>  
> -#if __has_builtin(__builtin_is_pointer_interconvertible_with_class)
> +#if 
> _GLIBCXX_HAS_BUILTIN_TRAIT(__builtin_is_pointer_interconvertible_with_class)
>  #define __cpp_lib_is_pointer_interconvertible 201907L
>  
>/// True if `__mp` points to the first member of a standard-layout type
> @@ -3590,8 +3590,8 @@ template
>template
>  inline constexpr bool is_scoped_enum_v = is_scoped_enum<_Tp>::value;
>  
> -#if __has_builtin(__reference_constructs_from_temporary) \
> -  &&

Re: [pushed] c++: auto function as function argument [PR105779]

2022-06-30 Thread Patrick Palka via Gcc-patches
On Wed, Jun 1, 2022 at 3:21 PM Jason Merrill via Gcc-patches
 wrote:
>
> This testcase demonstrates that the issue in PR105623 is not limited to
> templates, so we should do the marking in a less template-specific place.
>
> Tested x86_64-pc-linux-gnu, applying to trunk.
>
> PR c++/105779
>
> gcc/cp/ChangeLog:
>
> * call.cc (resolve_args): Call mark_single_function here.
> * pt.cc (unify_one_argument): Not here.
>
> gcc/testsuite/ChangeLog:
>
> * g++.dg/cpp1y/auto-fn63.C: New test.
> ---
>  gcc/cp/call.cc |  5 +
>  gcc/cp/pt.cc   |  4 
>  gcc/testsuite/g++.dg/cpp1y/auto-fn63.C | 12 
>  3 files changed, 17 insertions(+), 4 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp1y/auto-fn63.C
>
> diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
> index 85fe9b5ab85..4710c3777c5 100644
> --- a/gcc/cp/call.cc
> +++ b/gcc/cp/call.cc
> @@ -4672,6 +4672,11 @@ resolve_args (vec *args, tsubst_flags_t 
> complain)
> }
>else if (invalid_nonstatic_memfn_p (EXPR_LOCATION (arg), arg, 
> complain))
> return NULL;
> +
> +  /* Force auto deduction now.  Omit tf_warning to avoid redundant
> +deprecated warning on deprecated-14.C.  */
> +  if (!mark_single_function (arg, tf_error))

I wonder why pass tf_error here instead of an appropriately masked 'complain'?


> +   return NULL;
>  }
>return args;
>  }
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 4f0ace2644b..6de8e496859 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -22624,10 +22624,6 @@ unify_one_argument (tree tparms, tree targs, tree 
> parm, tree arg,
>   return unify_success (explain_p);
> }
>
> - /* Force auto deduction now.  Use tf_none to avoid redundant
> -deprecated warning on deprecated-14.C.  */
> - mark_single_function (arg, tf_none);
> -
>   arg_expr = arg;
>   arg = unlowered_expr_type (arg);
>   if (arg == error_mark_node)
> diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn63.C 
> b/gcc/testsuite/g++.dg/cpp1y/auto-fn63.C
> new file mode 100644
> index 000..ca3bc854065
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn63.C
> @@ -0,0 +1,12 @@
> +// PR c++/105779
> +// { dg-do compile { target c++14 } }
> +
> +template
> +struct struct1
> +{
> +  static auto apply() { return 1; }
> +};
> +
> +int method(int(*f)());
> +
> +int t = method(struct1<1>::apply);
>
> base-commit: ae54c1b09963779c5c3914782324ff48af32e2f1
> --
> 2.27.0
>



Re: [PATCH] c++: generic targs and identity substitution [PR105956]

2022-07-05 Thread Patrick Palka via Gcc-patches
On Fri, 1 Jul 2022, Jason Merrill wrote:

> On 6/29/22 13:42, Patrick Palka wrote:
> > In r13-1045-gcb7fd1ea85feea I assumed that substitution into generic
> > DECL_TI_ARGS corresponds to an identity mapping of the given arguments,
> > and hence its safe to always elide such substitution.  But this PR
> > demonstrates that such a substitution isn't always the identity mapping,
> > in particular when there's an ARGUMENT_PACK_SELECT argument, which gets
> > handled specially during substitution:
> > 
> >* when substituting an APS into a template parameter, we strip the
> >  APS to its underlying argument;
> >* and when substituting an APS into a pack expansion, we strip the
> >  APS to its underlying argument pack.
> 
> Ah, right.  For instance, in variadic96.C we have
> 
> 10template < typename... T >
> 11struct derived
> 12  : public base< T, derived< T... > >...
> 
> so when substituting into the base-specifier, we're approaching it from the
> outside in, so when we get to the inner T... we need some way to find the T
> pack again.  It might be possible to remove the need for APS by substituting
> inner pack expansions before outer ones, which could improve worst-case
> complexity, but I don't know how relevant that is in real code; I imagine most
> inner pack expansions are as simple as this one.

Aha, that makes sense.

> 
> > In this testcase, when expanding the pack expansion pattern (idx + Ns)...
> > with Ns={0,1}, we specialize idx twice, first with Ns=APS<0,{0,1}> and
> > then Ns=APS<1,{0,1}>.  The DECL_TI_ARGS of idx are the generic template
> > arguments of the enclosing class template impl, so before r13-1045,
> > we'd substitute into its DECL_TI_ARGS which gave Ns={0,1} as desired.
> > But after r13-1045, we elide this substitution and end up attempting to
> > hash the original Ns argument, an APS, which ICEs.
> > 
> > So this patch partially reverts this part of r13-1045.  I considered
> > using preserve_args in this case instead, but that'd break the
> > static_assert in the testcase because preserve_args always strips APS to
> > its underlying argument, but here we want to strip it to its underlying
> > argument pack, so we'd incorrectly end up forming the specializations
> > impl<0>::idx and impl<1>::idx instead of impl<0,1>::idx.
> > 
> > Although we can't elide the substitution into DECL_TI_ARGS in light of
> > ARGUMENT_PACK_SELECT, it should still be safe to elide template argument
> > coercion in the case of a non-template decl, which this patch preserves.
> > 
> > It's unfortunate that we need to remove this optimization just because
> > it doesn't hold for one special tree code.  So this patch implements a
> > heuristic in tsubst_template_args to avoid allocating a new TREE_VEC if
> > the substituted elements are identical to those of a level from ARGS.
> > It turns out that about 30% of all calls to tsubst_template_args benefit
> > from this optimization, and it reduces memory usage by about 1.5% for
> > e.g. stdc++.h (relative to r13-1045).  (This is the maybe_reuse stuff,
> > the rest of the changes to tsubst_template_args are just drive-by
> > cleanups.)
> > 
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > trunk?  Patch generated with -w to ignore noisy whitespace changes.
> > 
> > PR c++/105956
> > 
> > gcc/cp/ChangeLog:
> > 
> > * pt.cc (tsubst_template_args): Move variable declarations
> > closer to their first use.  Replace 'orig_t' with 'r'.  Rename
> > 'need_new' to 'const_subst_p'.  Heuristically detect if the
> > substituted elements are identical to that of a level from
> > 'args' and avoid allocating a new TREE_VEC if so.
> > (tsubst_decl) : Revert
> > r13-1045-gcb7fd1ea85feea change for avoiding substitution into
> > DECL_TI_ARGS, but still avoid coercion in this case.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/cpp0x/variadic183.C: New test.
> > ---
> >   gcc/cp/pt.cc | 113 ++-
> >   gcc/testsuite/g++.dg/cpp0x/variadic183.C |  14 +++
> >   2 files changed, 85 insertions(+), 42 deletions(-)
> >   create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic183.C
> > 
> > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > index 8672da123f4..7898834faa6 100644
> > --- a/gcc/cp/pt.cc
> > +++ b/gcc/cp/pt.cc
> > @@ -27,6 +27,7 @@ along with GCC; see the file COPYING3.  If not see
> >Fixed by: C++20 modules.  */
> > #include "config.h"
> > +#define INCLUDE_ALGORITHM // for std::equal
> >   #include "system.h"
> >   #include "coretypes.h"
> >   #include "cp-tree.h"
> > @@ -13544,17 +13545,22 @@ tsubst_argument_pack (tree orig_arg, tree args,
> > tsubst_flags_t complain,
> >   tree
> >   tsubst_template_args (tree t, tree args, tsubst_flags_t complain, tree
> > in_decl)
> >   {
> > -  tree orig_t = t;
> > -  int len, need_new = 0, i, expanded_len_adjust = 0, out;
> > -  tree *elts;
> > -
> > if (t

Re: [PATCH] c++: generic targs and identity substitution [PR105956]

2022-07-06 Thread Patrick Palka via Gcc-patches
On Tue, 5 Jul 2022, Jason Merrill wrote:

> On 7/5/22 10:06, Patrick Palka wrote:
> > On Fri, 1 Jul 2022, Jason Merrill wrote:
> > 
> > > On 6/29/22 13:42, Patrick Palka wrote:
> > > > In r13-1045-gcb7fd1ea85feea I assumed that substitution into generic
> > > > DECL_TI_ARGS corresponds to an identity mapping of the given arguments,
> > > > and hence its safe to always elide such substitution.  But this PR
> > > > demonstrates that such a substitution isn't always the identity mapping,
> > > > in particular when there's an ARGUMENT_PACK_SELECT argument, which gets
> > > > handled specially during substitution:
> > > > 
> > > > * when substituting an APS into a template parameter, we strip the
> > > >   APS to its underlying argument;
> > > > * and when substituting an APS into a pack expansion, we strip the
> > > >   APS to its underlying argument pack.
> > > 
> > > Ah, right.  For instance, in variadic96.C we have
> > > 
> > >  10   template < typename... T >
> > >  11   struct derived
> > >  12 : public base< T, derived< T... > >...
> > > 
> > > so when substituting into the base-specifier, we're approaching it from
> > > the
> > > outside in, so when we get to the inner T... we need some way to find the
> > > T
> > > pack again.  It might be possible to remove the need for APS by
> > > substituting
> > > inner pack expansions before outer ones, which could improve worst-case
> > > complexity, but I don't know how relevant that is in real code; I imagine
> > > most
> > > inner pack expansions are as simple as this one.
> > 
> > Aha, that makes sense.
> > 
> > > 
> > > > In this testcase, when expanding the pack expansion pattern (idx +
> > > > Ns)...
> > > > with Ns={0,1}, we specialize idx twice, first with Ns=APS<0,{0,1}> and
> > > > then Ns=APS<1,{0,1}>.  The DECL_TI_ARGS of idx are the generic template
> > > > arguments of the enclosing class template impl, so before r13-1045,
> > > > we'd substitute into its DECL_TI_ARGS which gave Ns={0,1} as desired.
> > > > But after r13-1045, we elide this substitution and end up attempting to
> > > > hash the original Ns argument, an APS, which ICEs.
> > > > 
> > > > So this patch partially reverts this part of r13-1045.  I considered
> > > > using preserve_args in this case instead, but that'd break the
> > > > static_assert in the testcase because preserve_args always strips APS to
> > > > its underlying argument, but here we want to strip it to its underlying
> > > > argument pack, so we'd incorrectly end up forming the specializations
> > > > impl<0>::idx and impl<1>::idx instead of impl<0,1>::idx.
> > > > 
> > > > Although we can't elide the substitution into DECL_TI_ARGS in light of
> > > > ARGUMENT_PACK_SELECT, it should still be safe to elide template argument
> > > > coercion in the case of a non-template decl, which this patch preserves.
> > > > 
> > > > It's unfortunate that we need to remove this optimization just because
> > > > it doesn't hold for one special tree code.  So this patch implements a
> > > > heuristic in tsubst_template_args to avoid allocating a new TREE_VEC if
> > > > the substituted elements are identical to those of a level from ARGS.
> > > > It turns out that about 30% of all calls to tsubst_template_args benefit
> > > > from this optimization, and it reduces memory usage by about 1.5% for
> > > > e.g. stdc++.h (relative to r13-1045).  (This is the maybe_reuse stuff,
> > > > the rest of the changes to tsubst_template_args are just drive-by
> > > > cleanups.)
> > > > 
> > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > > > trunk?  Patch generated with -w to ignore noisy whitespace changes.
> > > > 
> > > > PR c++/105956
> > > > 
> > > > gcc/cp/ChangeLog:
> > > > 
> > > > * pt.cc (tsubst_template_args): Move variable declarations
> > > > closer to their first use.  Replace 'orig_t' with 'r'.  Rename
> > > > 'need_new' to 'const_subst_p'.  Heuristically detect if the
> > > > substituted elements are identical to that of a level from
> > > > 'args' and avoid allocating a new TREE_VEC if so.
> > > > (tsubst_decl) : Revert
> > > > r13-1045-gcb7fd1ea85feea change for avoiding substitution into
> > > > DECL_TI_ARGS, but still avoid coercion in this case.
> > > > 
> > > > gcc/testsuite/ChangeLog:
> > > > 
> > > > * g++.dg/cpp0x/variadic183.C: New test.
> > > > ---
> > > >gcc/cp/pt.cc | 113
> > > > ++-
> > > >gcc/testsuite/g++.dg/cpp0x/variadic183.C |  14 +++
> > > >2 files changed, 85 insertions(+), 42 deletions(-)
> > > >create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic183.C
> > > > 
> > > > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > > > index 8672da123f4..7898834faa6 100644
> > > > --- a/gcc/cp/pt.cc
> > > > +++ b/gcc/cp/pt.cc
> > > > @@ -27,6 +27,7 @@ along with GCC; see the file COPYING3.  If not see
> > > > Fixed 

Re: [PATCH] c++: generic targs and identity substitution [PR105956]

2022-07-07 Thread Patrick Palka via Gcc-patches
On Thu, 7 Jul 2022, Jason Merrill wrote:

> On 7/6/22 15:26, Patrick Palka wrote:
> > On Tue, 5 Jul 2022, Jason Merrill wrote:
> > 
> > > On 7/5/22 10:06, Patrick Palka wrote:
> > > > On Fri, 1 Jul 2022, Jason Merrill wrote:
> > > > 
> > > > > On 6/29/22 13:42, Patrick Palka wrote:
> > > > > > In r13-1045-gcb7fd1ea85feea I assumed that substitution into generic
> > > > > > DECL_TI_ARGS corresponds to an identity mapping of the given
> > > > > > arguments,
> > > > > > and hence its safe to always elide such substitution.  But this PR
> > > > > > demonstrates that such a substitution isn't always the identity
> > > > > > mapping,
> > > > > > in particular when there's an ARGUMENT_PACK_SELECT argument, which
> > > > > > gets
> > > > > > handled specially during substitution:
> > > > > > 
> > > > > >  * when substituting an APS into a template parameter, we strip
> > > > > > the
> > > > > >APS to its underlying argument;
> > > > > >  * and when substituting an APS into a pack expansion, we strip
> > > > > > the
> > > > > >APS to its underlying argument pack.
> > > > > 
> > > > > Ah, right.  For instance, in variadic96.C we have
> > > > > 
> > > > >   10  template < typename... T >
> > > > >   11  struct derived
> > > > >   12: public base< T, derived< T... > >...
> > > > > 
> > > > > so when substituting into the base-specifier, we're approaching it
> > > > > from
> > > > > the
> > > > > outside in, so when we get to the inner T... we need some way to find
> > > > > the
> > > > > T
> > > > > pack again.  It might be possible to remove the need for APS by
> > > > > substituting
> > > > > inner pack expansions before outer ones, which could improve
> > > > > worst-case
> > > > > complexity, but I don't know how relevant that is in real code; I
> > > > > imagine
> > > > > most
> > > > > inner pack expansions are as simple as this one.
> > > > 
> > > > Aha, that makes sense.
> > > > 
> > > > > 
> > > > > > In this testcase, when expanding the pack expansion pattern (idx +
> > > > > > Ns)...
> > > > > > with Ns={0,1}, we specialize idx twice, first with Ns=APS<0,{0,1}>
> > > > > > and
> > > > > > then Ns=APS<1,{0,1}>.  The DECL_TI_ARGS of idx are the generic
> > > > > > template
> > > > > > arguments of the enclosing class template impl, so before r13-1045,
> > > > > > we'd substitute into its DECL_TI_ARGS which gave Ns={0,1} as
> > > > > > desired.
> > > > > > But after r13-1045, we elide this substitution and end up attempting
> > > > > > to
> > > > > > hash the original Ns argument, an APS, which ICEs.
> > > > > > 
> > > > > > So this patch partially reverts this part of r13-1045.  I considered
> > > > > > using preserve_args in this case instead, but that'd break the
> > > > > > static_assert in the testcase because preserve_args always strips
> > > > > > APS to
> > > > > > its underlying argument, but here we want to strip it to its
> > > > > > underlying
> > > > > > argument pack, so we'd incorrectly end up forming the
> > > > > > specializations
> > > > > > impl<0>::idx and impl<1>::idx instead of impl<0,1>::idx.
> > > > > > 
> > > > > > Although we can't elide the substitution into DECL_TI_ARGS in light
> > > > > > of
> > > > > > ARGUMENT_PACK_SELECT, it should still be safe to elide template
> > > > > > argument
> > > > > > coercion in the case of a non-template decl, which this patch
> > > > > > preserves.
> > > > > > 
> > > > > > It's unfortunate that we need to remove this optimization just
> > > > > > because
> > > > > > it doesn't hold for one special tree code.  So this patch implements
> > > > > > a
> > > > > > heuristic in tsubst_template_args to avoid allocating a new TREE_VEC
> > > > > > if
> > > > > > the substituted elements are identical to those of a level from
> > > > > > ARGS.
> > > > > > It turns out that about 30% of all calls to tsubst_template_args
> > > > > > benefit
> > > > > > from this optimization, and it reduces memory usage by about 1.5%
> > > > > > for
> > > > > > e.g. stdc++.h (relative to r13-1045).  (This is the maybe_reuse
> > > > > > stuff,
> > > > > > the rest of the changes to tsubst_template_args are just drive-by
> > > > > > cleanups.)
> > > > > > 
> > > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
> > > > > > for
> > > > > > trunk?  Patch generated with -w to ignore noisy whitespace changes.
> > > > > > 
> > > > > > PR c++/105956
> > > > > > 
> > > > > > gcc/cp/ChangeLog:
> > > > > > 
> > > > > > * pt.cc (tsubst_template_args): Move variable declarations
> > > > > > closer to their first use.  Replace 'orig_t' with 'r'.  Rename
> > > > > > 'need_new' to 'const_subst_p'.  Heuristically detect if the
> > > > > > substituted elements are identical to that of a level from
> > > > > > 'args' and avoid allocating a new TREE_VEC if so.
> > > > > > (tsubst_decl) : Revert
> > > > > > r13-1045-gcb7fd1ea85feea change for avoiding substitution into
> > > > > > DECL

Re: [PATCH] c++: generic targs and identity substitution [PR105956]

2022-07-07 Thread Patrick Palka via Gcc-patches
On Thu, 7 Jul 2022, Patrick Palka wrote:

> On Thu, 7 Jul 2022, Jason Merrill wrote:
> 
> > On 7/6/22 15:26, Patrick Palka wrote:
> > > On Tue, 5 Jul 2022, Jason Merrill wrote:
> > > 
> > > > On 7/5/22 10:06, Patrick Palka wrote:
> > > > > On Fri, 1 Jul 2022, Jason Merrill wrote:
> > > > > 
> > > > > > On 6/29/22 13:42, Patrick Palka wrote:
> > > > > > > In r13-1045-gcb7fd1ea85feea I assumed that substitution into 
> > > > > > > generic
> > > > > > > DECL_TI_ARGS corresponds to an identity mapping of the given
> > > > > > > arguments,
> > > > > > > and hence its safe to always elide such substitution.  But this PR
> > > > > > > demonstrates that such a substitution isn't always the identity
> > > > > > > mapping,
> > > > > > > in particular when there's an ARGUMENT_PACK_SELECT argument, which
> > > > > > > gets
> > > > > > > handled specially during substitution:
> > > > > > > 
> > > > > > >  * when substituting an APS into a template parameter, we 
> > > > > > > strip
> > > > > > > the
> > > > > > >APS to its underlying argument;
> > > > > > >  * and when substituting an APS into a pack expansion, we 
> > > > > > > strip
> > > > > > > the
> > > > > > >APS to its underlying argument pack.
> > > > > > 
> > > > > > Ah, right.  For instance, in variadic96.C we have
> > > > > > 
> > > > > >   10template < typename... T >
> > > > > >   11struct derived
> > > > > >   12  : public base< T, derived< T... > >...
> > > > > > 
> > > > > > so when substituting into the base-specifier, we're approaching it
> > > > > > from
> > > > > > the
> > > > > > outside in, so when we get to the inner T... we need some way to 
> > > > > > find
> > > > > > the
> > > > > > T
> > > > > > pack again.  It might be possible to remove the need for APS by
> > > > > > substituting
> > > > > > inner pack expansions before outer ones, which could improve
> > > > > > worst-case
> > > > > > complexity, but I don't know how relevant that is in real code; I
> > > > > > imagine
> > > > > > most
> > > > > > inner pack expansions are as simple as this one.
> > > > > 
> > > > > Aha, that makes sense.
> > > > > 
> > > > > > 
> > > > > > > In this testcase, when expanding the pack expansion pattern (idx +
> > > > > > > Ns)...
> > > > > > > with Ns={0,1}, we specialize idx twice, first with Ns=APS<0,{0,1}>
> > > > > > > and
> > > > > > > then Ns=APS<1,{0,1}>.  The DECL_TI_ARGS of idx are the generic
> > > > > > > template
> > > > > > > arguments of the enclosing class template impl, so before 
> > > > > > > r13-1045,
> > > > > > > we'd substitute into its DECL_TI_ARGS which gave Ns={0,1} as
> > > > > > > desired.
> > > > > > > But after r13-1045, we elide this substitution and end up 
> > > > > > > attempting
> > > > > > > to
> > > > > > > hash the original Ns argument, an APS, which ICEs.
> > > > > > > 
> > > > > > > So this patch partially reverts this part of r13-1045.  I 
> > > > > > > considered
> > > > > > > using preserve_args in this case instead, but that'd break the
> > > > > > > static_assert in the testcase because preserve_args always strips
> > > > > > > APS to
> > > > > > > its underlying argument, but here we want to strip it to its
> > > > > > > underlying
> > > > > > > argument pack, so we'd incorrectly end up forming the
> > > > > > > specializations
> > > > > > > impl<0>::idx and impl<1>::idx instead of impl<0,1>::idx.
> > > > > > > 
> > > > > > > Although we can't elide the substitution into DECL_TI_ARGS in 
> > > > > > > light
> > > > > > > of
> > > > > > > ARGUMENT_PACK_SELECT, it should still be safe to elide template
> > > > > > > argument
> > > > > > > coercion in the case of a non-template decl, which this patch
> > > > > > > preserves.
> > > > > > > 
> > > > > > > It's unfortunate that we need to remove this optimization just
> > > > > > > because
> > > > > > > it doesn't hold for one special tree code.  So this patch 
> > > > > > > implements
> > > > > > > a
> > > > > > > heuristic in tsubst_template_args to avoid allocating a new 
> > > > > > > TREE_VEC
> > > > > > > if
> > > > > > > the substituted elements are identical to those of a level from
> > > > > > > ARGS.
> > > > > > > It turns out that about 30% of all calls to tsubst_template_args
> > > > > > > benefit
> > > > > > > from this optimization, and it reduces memory usage by about 1.5%
> > > > > > > for
> > > > > > > e.g. stdc++.h (relative to r13-1045).  (This is the maybe_reuse
> > > > > > > stuff,
> > > > > > > the rest of the changes to tsubst_template_args are just drive-by
> > > > > > > cleanups.)
> > > > > > > 
> > > > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look 
> > > > > > > OK
> > > > > > > for
> > > > > > > trunk?  Patch generated with -w to ignore noisy whitespace 
> > > > > > > changes.
> > > > > > > 
> > > > > > >   PR c++/105956
> > > > > > > 
> > > > > > > gcc/cp/ChangeLog:
> > > > > > > 
> > > > > > >   * pt.cc (tsubst_template_args): Move variable declarations
> > > > > > 

[PATCH] c++: dependence of constrained memfn from current inst [PR105842]

2022-07-11 Thread Patrick Palka via Gcc-patches
Here we incorrectly deem the calls to func1, func2 and tmpl2 as
ambiguous ahead of time ultimately because we mishandle dependence
of a constrained member function from the current instantiation.

In type_dependent_expression_p, we consider the dependence of a
TEMPLATE_DECL's constraints (via uses_outer_template_parms), but
neglect to do the same for a FUNCTION_DECL such as func1.

And in satisfy_declaration_constraints, we give up if _any_ template
argument is dependent, but for non-dependent member functions from
the current instantiation such as func2 and tmpl2, we can and must
check constraints as long as the innermost arguments aren't dependent.

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

PR c++/105842

gcc/cp/ChangeLog:

* constraint.cc (satisfy_declaration_constraints): Refine
early exit test for argument dependence.
* cp-tree.h (uses_outer_template_parms_in_constraints): Declare.
* pt.cc (template_class_depth): Handle TI_TEMPLATE being a
FIELD_DECL.
(usse_outer_template_parms): Factor out constraint dependence
check to ...
(uses_outer_template_parms_in_constraints): ... here.
(type_dependent_expression_p): Use it for FUNCTION_DECL.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts-memtmpl6.C: New test.
---
 gcc/cp/constraint.cc  | 20 +++
 gcc/cp/cp-tree.h  |  1 +
 gcc/cp/pt.cc  | 34 ---
 .../g++.dg/cpp2a/concepts-memtmpl6.C  | 34 +++
 4 files changed, 79 insertions(+), 10 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-memtmpl6.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 591155cee22..99b97d24eae 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3176,9 +3176,13 @@ satisfy_declaration_constraints (tree t, sat_info info)
args = regen_args;
 }
 
-  /* If any arguments depend on template parameters, we can't
- check constraints. Pretend they're satisfied for now.  */
-  if (uses_template_parms (args))
+  /* If the innermost arguments are dependent, or if the outer arguments
+ are dependent and are needed by the constraints, we can't check
+ satisfaction yet so pretend they're satisfied for now.  */
+  if (uses_template_parms (args)
+  && (TMPL_ARGS_DEPTH (args) == 1
+ || uses_template_parms (INNERMOST_TEMPLATE_ARGS (args))
+ || uses_outer_template_parms_in_constraints (t)))
 return boolean_true_node;
 
   /* Get the normalized constraints.  */
@@ -3240,9 +3244,13 @@ satisfy_declaration_constraints (tree t, tree args, 
sat_info info)
   else
 args = add_outermost_template_args (t, args);
 
-  /* If any arguments depend on template parameters, we can't
- check constraints. Pretend they're satisfied for now.  */
-  if (uses_template_parms (args))
+  /* If the innermost arguments are dependent, or if the outer arguments
+ are dependent and are needed by the constraints, we can't check
+ satisfaction yet so pretend they're satisfied for now.  */
+  if (uses_template_parms (args)
+  && (TMPL_ARGS_DEPTH (args) == 1
+ || uses_template_parms (INNERMOST_TEMPLATE_ARGS (args))
+ || uses_outer_template_parms_in_constraints (t)))
 return boolean_true_node;
 
   tree result = boolean_true_node;
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 2fde4f83b41..bec98aa2ac3 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7297,6 +7297,7 @@ extern tree lookup_template_function  (tree, 
tree);
 extern tree lookup_template_variable   (tree, tree);
 extern bool uses_template_parms(tree);
 extern bool uses_template_parms_level  (tree, int);
+extern bool uses_outer_template_parms_in_constraints (tree);
 extern bool in_template_function   (void);
 extern bool need_generic_capture   (void);
 extern tree instantiate_class_template (tree);
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 59ee50c152d..de5d3a5cd78 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -391,7 +391,9 @@ template_class_depth (tree type)
 {
   tree tinfo = get_template_info (type);
 
-  if (tinfo && PRIMARY_TEMPLATE_P (TI_TEMPLATE (tinfo))
+  if (tinfo
+ && TREE_CODE (TI_TEMPLATE (tinfo)) == TEMPLATE_DECL
+ && PRIMARY_TEMPLATE_P (TI_TEMPLATE (tinfo))
  && uses_template_parms (INNERMOST_TEMPLATE_ARGS (TI_ARGS (tinfo
++depth;
 
@@ -11011,7 +11013,7 @@ uses_template_parms_level (tree t, int level)
 /* Returns true if the signature of DECL depends on any template parameter from
its enclosing class.  */
 
-bool
+static bool
 uses_outer_template_parms (tree decl)
 {
   int depth = template_class_depth (CP_DECL_CONTEXT (decl));
@@ -11042,11 +11044,27 @@ uses_outer_template_parms (tree decl)
return true;
}
 }
+  if (us

[PATCH] c++: non-dependent call to consteval operator [PR105912]

2022-07-11 Thread Patrick Palka via Gcc-patches
Here we were crashing when substituting a non-dependent call to a
consteval operator, whose CALL_EXPR_OPERATOR_SYNTAX flag we try to
propagate to the result, but the result isn't a CALL_EXPR since the
called function is consteval.  This patch fixes this by checking the
result of extract_call_expr accordingly.  (Note that we can't easily
check DECL_IMMEDIATE_FUNCTION_P here because we don't know which
function was selected by overload resolution from this call frame.)

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

PR c++/105912

gcc/cp/ChangeLog:

* pt.cc (tsubst_copy_and_build) : Guard against
NULL_TREE extract_call_expr result.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/consteval31.C: New test.
---
 gcc/cp/pt.cc | 10 +
 gcc/testsuite/g++.dg/cpp2a/consteval31.C | 26 
 2 files changed, 32 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/consteval31.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 232964c2831..8a6ae5c42fe 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -21207,10 +21207,12 @@ tsubst_copy_and_build (tree t,
bool rev = CALL_EXPR_REVERSE_ARGS (t);
if (op || ord || rev)
  {
-   function = extract_call_expr (ret);
-   CALL_EXPR_OPERATOR_SYNTAX (function) = op;
-   CALL_EXPR_ORDERED_ARGS (function) = ord;
-   CALL_EXPR_REVERSE_ARGS (function) = rev;
+   if (tree call = extract_call_expr (ret))
+ {
+   CALL_EXPR_OPERATOR_SYNTAX (call) = op;
+   CALL_EXPR_ORDERED_ARGS (call) = ord;
+   CALL_EXPR_REVERSE_ARGS (call) = rev;
+ }
  }
  }
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval31.C 
b/gcc/testsuite/g++.dg/cpp2a/consteval31.C
new file mode 100644
index 000..85a4d1794e5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/consteval31.C
@@ -0,0 +1,26 @@
+// PR c++/105912
+// { dg-do compile { target c++20 } }
+
+struct A {
+  consteval A operator+() {
+return {};
+  }
+};
+
+consteval A operator~(A) {
+  return {};
+}
+
+consteval A operator+(A, A) {
+  return {};
+}
+
+template
+void f() {
+  A a;
+  ~a;
+  a + a;
+  +a;
+}
+
+template void f();
-- 
2.37.0.3.g30cc8d0f14



[PATCH] c++: shortcut bad reference bindings [PR94894]

2022-07-18 Thread Patrick Palka via Gcc-patches
In case of l/rvalue or cv-qual mismatch during reference binding, we try
to give more helpful diagnostics by attempting a bad conversion that
ignores the mismatch.  But in doing so, we may end up instantiating an
ill-formed conversion function, something that would otherwise be
avoided if we didn't try for the better diagnostic in the first place.
We could just give up on producing a good diagnostic in this case, but
ideally we could keep the good diagnostics while avoiding unnecessary
template instantiations.

To that end, this patch adapts the bad conversion shortcutting mechanism
from r12-3346-g47543e5f9d1fc5 to handle this situation as well.  The main
observation from there applies here as well: when there's a strictly
viable candidate, we don't care about the distinction between an unviable
and non-strictly viable candidate.  And in turn it also means we don't
really care about the distinction between an invalid and bad conversion.
Of course, we don't know whether there's a strictly viable candidate until
after the fact, so we still need to keep track of when we "shortcutted"
distinguishing between an invalid and bad conversion.  This patch adds a
new kind of conversion, ck_shortcutted, to represent such conversions.

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

PR c++/94894
PR c++/105766
PR c++/106201

gcc/cp/ChangeLog:

* call.cc (enum conversion_kind): Add ck_shortcutted enumerator.
(has_next): Return false for it.
(reference_binding): Return a ck_shortcutted conversion instead
of an actual bad conversion when LOOKUP_SHORTCUT_BAD_CONVS is set.
Remove now obsolete early exit for the incomplete target type case.
(implicit_conversion_1): Don't mask out LOOKUP_SHORTCUT_BAD_CONVS.
(add_function_candidate): Set LOOKUP_SHORTCUT_BAD_CONVS iff
shortcut_bad_convs.
(missing_conversion_p): Return true for a ck_shortcutted
conversion.
* cp-tree.h (LOOKUP_SHORTCUT_BAD_CONVS): Define.

gcc/testsuite/ChangeLog:

* g++.dg/conversion/ref8.C: New test.
* g++.dg/conversion/ref9.C: New test.
---
 gcc/cp/call.cc | 87 --
 gcc/cp/cp-tree.h   |  5 ++
 gcc/testsuite/g++.dg/conversion/ref8.C | 22 +++
 gcc/testsuite/g++.dg/conversion/ref9.C | 21 +++
 4 files changed, 103 insertions(+), 32 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/conversion/ref8.C
 create mode 100644 gcc/testsuite/g++.dg/conversion/ref9.C

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index fc98552fda2..ca2f5fbca39 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -59,7 +59,8 @@ enum conversion_kind {
   ck_ambig,
   ck_list,
   ck_aggr,
-  ck_rvalue
+  ck_rvalue,
+  ck_shortcutted,
 };
 
 /* The rank of the conversion.  Order of the enumerals matters; better
@@ -775,7 +776,8 @@ has_next (conversion_kind code)
   return !(code == ck_identity
   || code == ck_ambig
   || code == ck_list
-  || code == ck_aggr);
+  || code == ck_aggr
+  || code == ck_shortcutted);
 }
 
 static conversion *
@@ -1912,18 +1914,38 @@ reference_binding (tree rto, tree rfrom, tree expr, 
bool c_cast_p, int flags,
  difference in top-level cv-qualification is subsumed by the
  initialization itself and does not constitute a conversion.  */
 
+  bool maybe_valid_p = true;
+
   /* [dcl.init.ref]
 
  Otherwise, the reference shall be an lvalue reference to a
  non-volatile const type, or the reference shall be an rvalue
- reference.
+ reference.  */
+  if (!CP_TYPE_CONST_NON_VOLATILE_P (to) && !TYPE_REF_IS_RVALUE (rto))
+maybe_valid_p = false;
 
- We try below to treat this as a bad conversion to improve diagnostics,
- but if TO is an incomplete class, we need to reject this conversion
- now to avoid unnecessary instantiation.  */
-  if (!CP_TYPE_CONST_NON_VOLATILE_P (to) && !TYPE_REF_IS_RVALUE (rto)
-  && !COMPLETE_TYPE_P (to))
-return NULL;
+  /* [dcl.init.ref]
+
+ Otherwise, a temporary of type "cv1 T1" is created and
+ initialized from the initializer expression using the rules for a
+ non-reference copy initialization.  If T1 is reference-related to
+ T2, cv1 must be the same cv-qualification as, or greater
+ cv-qualification than, cv2; otherwise, the program is ill-formed.  */
+  if (related_p && !at_least_as_qualified_p (to, from))
+maybe_valid_p = false;
+
+  /* We try below to treat an invalid reference binding as a bad conversion
+ to improve diagnostics, but doing so may cause otherwise unnecessary
+ instantiations that can lead to hard error.  So during the first pass
+ of overload resolution wherein we shortcut bad conversions, instead just
+ produce a special conversion that we'll use to indicate we might need to
+ perform a second pass if there's no strictly viable candidate.  */
+  if (!maybe_va

Re: [PATCH] c++: shortcut bad reference bindings [PR94894]

2022-07-19 Thread Patrick Palka via Gcc-patches
On Mon, 18 Jul 2022, Jason Merrill wrote:

> On 7/18/22 12:59, Patrick Palka wrote:
> > In case of l/rvalue or cv-qual mismatch during reference binding, we try
> > to give more helpful diagnostics by attempting a bad conversion that
> > ignores the mismatch.  But in doing so, we may end up instantiating an
> > ill-formed conversion function, something that would otherwise be
> > avoided if we didn't try for the better diagnostic in the first place.
> > We could just give up on producing a good diagnostic in this case, but
> > ideally we could keep the good diagnostics while avoiding unnecessary
> > template instantiations.
> > 
> > To that end, this patch adapts the bad conversion shortcutting mechanism
> > from r12-3346-g47543e5f9d1fc5 to handle this situation as well.  The main
> > observation from there applies here as well: when there's a strictly
> > viable candidate, we don't care about the distinction between an unviable
> > and non-strictly viable candidate.  And in turn it also means we don't
> > really care about the distinction between an invalid and bad conversion.
> > Of course, we don't know whether there's a strictly viable candidate until
> > after the fact, so we still need to keep track of when we "shortcutted"
> > distinguishing between an invalid and bad conversion.  This patch adds a
> > new kind of conversion, ck_shortcutted, to represent such conversions.
> > 
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > trunk?
> > 
> > PR c++/94894
> > PR c++/105766
> > PR c++/106201
> > 
> > gcc/cp/ChangeLog:
> > 
> > * call.cc (enum conversion_kind): Add ck_shortcutted enumerator.
> > (has_next): Return false for it.
> > (reference_binding): Return a ck_shortcutted conversion instead
> > of an actual bad conversion when LOOKUP_SHORTCUT_BAD_CONVS is set.
> > Remove now obsolete early exit for the incomplete target type case.
> > (implicit_conversion_1): Don't mask out LOOKUP_SHORTCUT_BAD_CONVS.
> > (add_function_candidate): Set LOOKUP_SHORTCUT_BAD_CONVS iff
> > shortcut_bad_convs.
> > (missing_conversion_p): Return true for a ck_shortcutted
> > conversion.
> > * cp-tree.h (LOOKUP_SHORTCUT_BAD_CONVS): Define.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/conversion/ref8.C: New test.
> > * g++.dg/conversion/ref9.C: New test.
> > ---
> >   gcc/cp/call.cc | 87 --
> >   gcc/cp/cp-tree.h   |  5 ++
> >   gcc/testsuite/g++.dg/conversion/ref8.C | 22 +++
> >   gcc/testsuite/g++.dg/conversion/ref9.C | 21 +++
> >   4 files changed, 103 insertions(+), 32 deletions(-)
> >   create mode 100644 gcc/testsuite/g++.dg/conversion/ref8.C
> >   create mode 100644 gcc/testsuite/g++.dg/conversion/ref9.C
> > 
> > diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
> > index fc98552fda2..ca2f5fbca39 100644
> > --- a/gcc/cp/call.cc
> > +++ b/gcc/cp/call.cc
> > @@ -59,7 +59,8 @@ enum conversion_kind {
> > ck_ambig,
> > ck_list,
> > ck_aggr,
> > -  ck_rvalue
> > +  ck_rvalue,
> > +  ck_shortcutted,
> 
> Please give this a comment explaining how it's used.  OK with that change.

Done.

> 
> Maybe ck_deferred_bad?

Ah nice, I like this much better than ck_shortcutted.  Here's what I
ended up pushing, thanks a lot:

-- >8 --

Subject: [PATCH] c++: shortcut bad reference binding [PR94894]

In case of l/rvalue or cv-qual mismatch during reference binding, we
try to give more helpful diagnostics by computing a bad conversion that
allows the mismatch.  But in doing so, we may end up considering and
instantiating a conversion function that could induce a hard error and
in turn cause us to reject otherwise valid code.  We could just give up
on producing a better diagnostic here, but ideally we'd preserve the
better diagnostics for invalid code while avoiding unnecessary template
instantiations for valid code.

To that end, this patch adapts the bad conversion shortcutting mechanism
from r12-3346-g47543e5f9d1fc5 to additionally handle this situation.
The main observation from there is that during overload resolution, if we
know we have a strictly viable candidate then we don't need to distinguish
between an unviable and non-strictly viable candidate.  Thus we don't
need to distinguish between an invalid and bad conversion either, which
is what this patch exploits.  Of course, we don't know whether we have a
strictly viable candidate until after the fact, so we still need to
remember when we deferred distinguishing between an invalid and bad
conversion.  This patch adds a special conversion kind ck_deferred_bad
for this purpose.

PR c++/94894
PR c++/105766
PR c++/106201

gcc/cp/ChangeLog:

* call.cc (enum conversion_kind): Add ck_deferred_bad enumerator.
(has_next): Return false for it.
(reference_binding): Return a ck_deferred_bad conversion instead
of an actual bad conversion when LOOKUP_SHORTCUT

[PATCH] c++: CTAD from initializer list [PR106366]

2022-07-21 Thread Patrick Palka via Gcc-patches
During CTAD, we currently perform the first phase of overload resolution
from [over.match.list] only if the class template has a list constructor.
But according to [over.match.class.deduct]/4 it should be enough to just
have a guide that looks like a list constructor (which is a more general
criterion in light of user-defined guides).

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

PR c++/106366

gcc/cp/ChangeLog:

* pt.cc (do_class_deduction): Don't consider TYPE_HAS_LIST_CTOR
when setting try_list_ctor.  Reset args even when try_list_ctor
is true and there are no list candidates.  Call resolve_args on
the reset args.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/class-deduction112.C: New test.
---
 gcc/cp/pt.cc  | 25 +--
 .../g++.dg/cpp1z/class-deduction112.C | 14 +++
 2 files changed, 26 insertions(+), 13 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction112.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 718dfa5bfa8..0f26d6f5bce 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -30250,8 +30250,8 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
   else if (BRACE_ENCLOSED_INITIALIZER_P (init))
 {
   list_init_p = true;
-  try_list_ctor = TYPE_HAS_LIST_CTOR (type);
-  if (try_list_ctor && CONSTRUCTOR_NELTS (init) == 1
+  try_list_ctor = true;
+  if (CONSTRUCTOR_NELTS (init) == 1
  && !CONSTRUCTOR_IS_DESIGNATED_INIT (init))
{
  /* As an exception, the first phase in 16.3.1.7 (considering the
@@ -30310,26 +30310,25 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
 
   tree fndecl = error_mark_node;
 
-  /* If this is list-initialization and the class has a list constructor, first
+  /* If this is list-initialization and the class has a list guide, first
  try deducing from the list as a single argument, as [over.match.list].  */
-  tree list_cands = NULL_TREE;
-  if (try_list_ctor && cands)
-for (lkp_iterator iter (cands); iter; ++iter)
-  {
-   tree dg = *iter;
+  if (try_list_ctor)
+{
+  tree list_cands = NULL_TREE;
+  for (tree dg : lkp_range (cands))
if (is_list_ctor (dg))
  list_cands = lookup_add (dg, list_cands);
-  }
-  if (list_cands)
-{
-  fndecl = perform_dguide_overload_resolution (list_cands, args, tf_none);
-
+  if (list_cands)
+   fndecl = perform_dguide_overload_resolution (list_cands, args, tf_none);
   if (fndecl == error_mark_node)
{
  /* That didn't work, now try treating the list as a sequence of
 arguments.  */
  release_tree_vector (args);
  args = make_tree_vector_from_ctor (init);
+ args = resolve_args (args, complain);
+ if (args == NULL)
+   return error_mark_node;
}
 }
 
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction112.C 
b/gcc/testsuite/g++.dg/cpp1z/class-deduction112.C
new file mode 100644
index 000..8da5868ff98
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction112.C
@@ -0,0 +1,14 @@
+// PR c++/106366
+// { dg-do compile { target c++17 } }
+
+#include 
+
+template
+struct A { A(...); };
+
+template
+A(std::initializer_list) -> A;
+
+A a{1,2,3};
+using type = decltype(a);
+using type = A;
-- 
2.37.1.208.ge72d93e88c



Re: [PATCH] c++: CTAD from initializer list [PR106366]

2022-07-21 Thread Patrick Palka via Gcc-patches
On Thu, 21 Jul 2022, Patrick Palka wrote:

> During CTAD, we currently perform the first phase of overload resolution
> from [over.match.list] only if the class template has a list constructor.
> But according to [over.match.class.deduct]/4 it should be enough to just
> have a guide that looks like a list constructor (which is a more general
> criterion in light of user-defined guides).
> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk?
> 
>   PR c++/106366
> 
> gcc/cp/ChangeLog:
> 
>   * pt.cc (do_class_deduction): Don't consider TYPE_HAS_LIST_CTOR
>   when setting try_list_ctor.  Reset args even when try_list_ctor
>   is true and there are no list candidates.  Call resolve_args on
>   the reset args.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp1z/class-deduction112.C: New test.
> ---
>  gcc/cp/pt.cc  | 25 +--
>  .../g++.dg/cpp1z/class-deduction112.C | 14 +++
>  2 files changed, 26 insertions(+), 13 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction112.C
> 
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 718dfa5bfa8..0f26d6f5bce 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -30250,8 +30250,8 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
>else if (BRACE_ENCLOSED_INITIALIZER_P (init))
>  {
>list_init_p = true;
> -  try_list_ctor = TYPE_HAS_LIST_CTOR (type);
> -  if (try_list_ctor && CONSTRUCTOR_NELTS (init) == 1
> +  try_list_ctor = true;

I suppose try_list_cand would be a more appropriate name for this
variable now, consider that fixed.

> +  if (CONSTRUCTOR_NELTS (init) == 1
> && !CONSTRUCTOR_IS_DESIGNATED_INIT (init))
>   {
> /* As an exception, the first phase in 16.3.1.7 (considering the
> @@ -30310,26 +30310,25 @@ do_class_deduction (tree ptype, tree tmpl, tree 
> init,
>  
>tree fndecl = error_mark_node;
>  
> -  /* If this is list-initialization and the class has a list constructor, 
> first
> +  /* If this is list-initialization and the class has a list guide, first
>   try deducing from the list as a single argument, as [over.match.list].  
> */
> -  tree list_cands = NULL_TREE;
> -  if (try_list_ctor && cands)
> -for (lkp_iterator iter (cands); iter; ++iter)
> -  {
> - tree dg = *iter;
> +  if (try_list_ctor)
> +{
> +  tree list_cands = NULL_TREE;
> +  for (tree dg : lkp_range (cands))
>   if (is_list_ctor (dg))
> list_cands = lookup_add (dg, list_cands);
> -  }
> -  if (list_cands)
> -{
> -  fndecl = perform_dguide_overload_resolution (list_cands, args, 
> tf_none);
> -
> +  if (list_cands)
> + fndecl = perform_dguide_overload_resolution (list_cands, args, tf_none);
>if (fndecl == error_mark_node)
>   {
> /* That didn't work, now try treating the list as a sequence of
>arguments.  */
> release_tree_vector (args);
> args = make_tree_vector_from_ctor (init);
> +   args = resolve_args (args, complain);
> +   if (args == NULL)
> + return error_mark_node;
>   }
>  }
>  
> diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction112.C 
> b/gcc/testsuite/g++.dg/cpp1z/class-deduction112.C
> new file mode 100644
> index 000..8da5868ff98
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction112.C
> @@ -0,0 +1,14 @@
> +// PR c++/106366
> +// { dg-do compile { target c++17 } }
> +
> +#include 
> +
> +template
> +struct A { A(...); };
> +
> +template
> +A(std::initializer_list) -> A;
> +
> +A a{1,2,3};
> +using type = decltype(a);
> +using type = A;
> -- 
> 2.37.1.208.ge72d93e88c
> 
> 



[PATCH] libstdc++: Fix backward compatibility of P2325R3 backport [PR106320]

2022-07-22 Thread Patrick Palka via Gcc-patches
The 11 and 10 partial backports of P2325R3, r11-9555-g92d6121eec and
r10-10808-g22b86cdc4d7fdd, unnecessarily preserved some changes from the
paper that made certain views no longer default constructible, changes
which aren't required to reap the overall benefits of the paper and
which conflicted with the goal to maximize backwards compatibility with
pre-P2325R3 code.

This patch reverts the problematic changes, specifically it relaxes
the constraints on various views' default constructors so that they
reflect only the requirements that were already implicitly imposed by
the NSDMIs of the view.  Thus for example this patch retains the
default_initializable<_Vp> constraint on transform_view's default
constructor since its '_Vp _M_base = _Vp()' NSDMI already reflects this
constraint, and it removes the default_initializable<_Fp> constraint
since the corresponding member '__detail::__box<_Fp> _M_fun' doesn't
require default initializability (specializations of __box are always
default constructible).

After reverting these changes, all static_asserts from p2325.cc that
verify lack of default constructibility now fail as expected, matching
the pre-P2325R3 behavior.

Tested on x86_64-pc-linux-gnu, does this look OK for the 11 and 10
branches?

PR libstdc++/106320

libstdc++-v3/ChangeLog:

* include/std/ranges (single_view): Remove
* testsuite/std/ranges/adaptors/join.cc (test13): New test.
* testsuite/std/ranges/p2325.cc: Fix S to be only non default
constructible and not also non copy constructible.  XFAIL the
tests that verify a non default constructible functor makes a
view non default constructible (lines 94, 97 and 98).  XFAIL
the test that effectively verifies a non default constructible
element type makes single_view non default constructible (line
114).
---
 libstdc++-v3/include/std/ranges| 18 +-
 .../testsuite/std/ranges/adaptors/join.cc  | 15 +++
 libstdc++-v3/testsuite/std/ranges/p2325.cc | 12 
 3 files changed, 28 insertions(+), 17 deletions(-)

diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index bbdfb7dbe5c..0a67c45f1b8 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -200,7 +200,7 @@ namespace ranges
 class single_view : public view_interface>
 {
 public:
-  single_view() requires default_initializable<_Tp> = default;
+  single_view() = default;
 
   constexpr explicit
   single_view(const _Tp& __t)
@@ -1463,9 +1463,7 @@ namespace views::__adaptor
   _Vp _M_base = _Vp();
 
 public:
-  filter_view() requires (default_initializable<_Vp>
- && default_initializable<_Pred>)
-   = default;
+  filter_view() requires default_initializable<_Vp> = default;
 
   constexpr
   filter_view(_Vp __base, _Pred __pred)
@@ -1829,9 +1827,7 @@ namespace views::__adaptor
   _Vp _M_base = _Vp();
 
 public:
-  transform_view() requires (default_initializable<_Vp>
-&& default_initializable<_Fp>)
-   = default;
+  transform_view() requires default_initializable<_Vp> = default;
 
   constexpr
   transform_view(_Vp __base, _Fp __fun)
@@ -2150,9 +2146,7 @@ namespace views::__adaptor
   _Vp _M_base = _Vp();
 
 public:
-  take_while_view() requires (default_initializable<_Vp>
- && default_initializable<_Pred>)
-   = default;
+  take_while_view() requires default_initializable<_Vp> = default;
 
   constexpr
   take_while_view(_Vp base, _Pred __pred)
@@ -2356,9 +2350,7 @@ namespace views::__adaptor
   _Vp _M_base = _Vp();
 
 public:
-  drop_while_view() requires (default_initializable<_Vp>
- && default_initializable<_Pred>)
-   = default;
+  drop_while_view() requires default_initializable<_Vp> = default;
 
   constexpr
   drop_while_view(_Vp __base, _Pred __pred)
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc 
b/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc
index d774e8d9385..14e254bc734 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc
@@ -193,6 +193,20 @@ test11()
 ;
 }
 
+void
+test13()
+{
+  // PR libstdc++/106320
+  auto l = std::views::transform([](auto x) {
+return x | std::views::transform([x=0](auto y) {
+  return y;
+});
+  });
+  static_assert(!std::default_initializable);
+  std::vector> v{{5, 6, 7}};
+  v | l | std::views::join;
+}
+
 int
 main()
 {
@@ -207,4 +221,5 @@ main()
   test09();
   test10();
   test11();
+  test13();
 }
diff --git a/libstdc++-v3/testsuite/std/ranges/p2325.cc 
b/libstdc++-v3/testsuite/std/ranges/p2325.cc
index 205b3458928..99f1b0f08f1 100644
--- a/libstdc++-v3/testsuite/std/ranges/p2325.cc
+++ b/libstdc++-v3/te

Re: [PATCH] libstdc++: Fix backward compatibility of P2325R3 backport [PR106320]

2022-07-22 Thread Patrick Palka via Gcc-patches
On Fri, Jul 22, 2022 at 11:52 AM Patrick Palka  wrote:
>
> The 11 and 10 partial backports of P2325R3, r11-9555-g92d6121eec and
> r10-10808-g22b86cdc4d7fdd, unnecessarily preserved some changes from the
> paper that made certain views no longer default constructible, changes
> which aren't required to reap the overall benefits of the paper and
> which conflicted with the goal to maximize backwards compatibility with
> pre-P2325R3 code.
>
> This patch reverts the problematic changes, specifically it relaxes
> the constraints on various views' default constructors so that they
> reflect only the requirements that were already implicitly imposed by
> the NSDMIs of the view.  Thus for example this patch retains the
> default_initializable<_Vp> constraint on transform_view's default
> constructor since its '_Vp _M_base = _Vp()' NSDMI already reflects this
> constraint, and it removes the default_initializable<_Fp> constraint
> since the corresponding member '__detail::__box<_Fp> _M_fun' doesn't
> require default initializability (specializations of __box are always
> default constructible).
>
> After reverting these changes, all static_asserts from p2325.cc that
> verify lack of default constructibility now fail as expected, matching
> the pre-P2325R3 behavior.
>
> Tested on x86_64-pc-linux-gnu, does this look OK for the 11 and 10
> branches?
>
> PR libstdc++/106320
>
> libstdc++-v3/ChangeLog:
>
> * include/std/ranges (single_view): Remove

Whoops I forgot to finish the changelog entry, will fix.

> * testsuite/std/ranges/adaptors/join.cc (test13): New test.
> * testsuite/std/ranges/p2325.cc: Fix S to be only non default
> constructible and not also non copy constructible.  XFAIL the
> tests that verify a non default constructible functor makes a
> view non default constructible (lines 94, 97 and 98).  XFAIL
> the test that effectively verifies a non default constructible
> element type makes single_view non default constructible (line
> 114).
> ---
>  libstdc++-v3/include/std/ranges| 18 +-
>  .../testsuite/std/ranges/adaptors/join.cc  | 15 +++
>  libstdc++-v3/testsuite/std/ranges/p2325.cc | 12 
>  3 files changed, 28 insertions(+), 17 deletions(-)
>
> diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
> index bbdfb7dbe5c..0a67c45f1b8 100644
> --- a/libstdc++-v3/include/std/ranges
> +++ b/libstdc++-v3/include/std/ranges
> @@ -200,7 +200,7 @@ namespace ranges
>  class single_view : public view_interface>
>  {
>  public:
> -  single_view() requires default_initializable<_Tp> = default;
> +  single_view() = default;
>
>constexpr explicit
>single_view(const _Tp& __t)
> @@ -1463,9 +1463,7 @@ namespace views::__adaptor
>_Vp _M_base = _Vp();
>
>  public:
> -  filter_view() requires (default_initializable<_Vp>
> - && default_initializable<_Pred>)
> -   = default;
> +  filter_view() requires default_initializable<_Vp> = default;
>
>constexpr
>filter_view(_Vp __base, _Pred __pred)
> @@ -1829,9 +1827,7 @@ namespace views::__adaptor
>_Vp _M_base = _Vp();
>
>  public:
> -  transform_view() requires (default_initializable<_Vp>
> -&& default_initializable<_Fp>)
> -   = default;
> +  transform_view() requires default_initializable<_Vp> = default;
>
>constexpr
>transform_view(_Vp __base, _Fp __fun)
> @@ -2150,9 +2146,7 @@ namespace views::__adaptor
>_Vp _M_base = _Vp();
>
>  public:
> -  take_while_view() requires (default_initializable<_Vp>
> - && default_initializable<_Pred>)
> -   = default;
> +  take_while_view() requires default_initializable<_Vp> = default;
>
>constexpr
>take_while_view(_Vp base, _Pred __pred)
> @@ -2356,9 +2350,7 @@ namespace views::__adaptor
>_Vp _M_base = _Vp();
>
>  public:
> -  drop_while_view() requires (default_initializable<_Vp>
> - && default_initializable<_Pred>)
> -   = default;
> +  drop_while_view() requires default_initializable<_Vp> = default;
>
>constexpr
>drop_while_view(_Vp __base, _Pred __pred)
> diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc 
> b/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc
> index d774e8d9385..14e254bc734 100644
> --- a/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc
> +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc
> @@ -193,6 +193,20 @@ test11()
>  ;
>  }
>
> +void
> +test13()
> +{
> +  // PR libstdc++/106320
> +  auto l = std::views::transform([](auto x) {
> +return x | std::views::transform([x=0](auto y) {
> +  return y;
> +});
> +  });
> +  static_assert(!std::default_initializable);
> +  std::vector> v{{5, 6, 7}};
> +  v | l 

Re: [PATCH 04/14] c++: use _P() defines from tree.h

2023-08-02 Thread Patrick Palka via Gcc-patches
On Thu, Jun 1, 2023 at 2:11 PM Bernhard Reutner-Fischer
 wrote:
>
> Hi David, Patrick,
>
> On Thu, 1 Jun 2023 18:33:46 +0200
> Bernhard Reutner-Fischer  wrote:
>
> > On Thu, 1 Jun 2023 11:24:06 -0400
> > Patrick Palka  wrote:
> >
> > > On Sat, May 13, 2023 at 7:26 PM Bernhard Reutner-Fischer via
> > > Gcc-patches  wrote:
> >
> > > > diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
> > > > index 131b212ff73..19dfb3ed782 100644
> > > > --- a/gcc/cp/tree.cc
> > > > +++ b/gcc/cp/tree.cc
> > > > @@ -1173,7 +1173,7 @@ build_cplus_array_type (tree elt_type, tree 
> > > > index_type, int dependent)
> > > >  }
> > > >
> > > >/* Avoid spurious warnings with VLAs (c++/54583).  */
> > > > -  if (TYPE_SIZE (t) && EXPR_P (TYPE_SIZE (t)))
> > > > +  if (CAN_HAVE_LOCATION_P (TYPE_SIZE (t)))
> > >
> > > Hmm, this change seems undesirable...
> >
> > mhm, yes that is misleading. I'll prepare a patch to revert this.
> > Let me have a look if there were other such CAN_HAVE_LOCATION_P changes
> > that we'd want to revert.
>
> Sorry for that!
> I'd revert the hunk above and the one in gcc-rich-location.cc
> (maybe_range_label_for_tree_type_mismatch::get_text), please see
> attached. Bootstrap running, ok for trunk if it passes?

LGTM!

>
> thanks,



[PATCH] c++: dependently scoped template-id in type-req [PR110927]

2023-08-10 Thread Patrick Palka via Gcc-patches
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
for trunk and perhaps 13?

-- >8 --

Here we're incorrectly rejecting the first type-requirement at parse
time with

  concepts-requires35.C:14:56: error: ‘typename A::B’ is not a template 
[-fpermissive]

We also incorrectly reject the second type-requirement at satisfaction time
with

  concepts-requires35.C:17:34: error: ‘typename A::B’ names 
‘template struct A::B’, which is not a type

and similarly for the third type-requirement.  This seems to happen only
within a type-requirement; if we instead use e.g. an alias template then
it works as expected.

The difference ultimately seems to be that during parsing of a
using-declaration, we pass check_dependency_p=true to
cp_parser_nested_name_specifier_opt whereas during parsing of a
type-requirement we pass check_dependency_p=false.  Passing =false causes
cp_parser_template_id for the dependently-scoped template-id B to
return a TYPE_DECL of TYPENAME_TYPE (sometimes with TYPENAME_IS_CLASS_P
unexpectedly set for the last two type-requirements) whereas passing
=true causes it to return a TEMPLATE_ID_EXPR.

The simplest fix therefore seems to be to pass check_dependency_p=true
from cp_parser_type_requirement, matching the behavior of
cp_parser_elaborated_type_specifier.

PR c++/110927

gcc/cp/ChangeLog:

* parser.cc (cp_parser_type_requirement): Pass
check_dependency_p=true instead of =false.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts-requires35.C: New test.
---
 gcc/cp/parser.cc  |  4 +--
 .../g++.dg/cpp2a/concepts-requires35.C| 28 +++
 2 files changed, 30 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-requires35.C

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 589ac879c6d..2d27376d988 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -30977,7 +30977,7 @@ cp_parser_type_requirement (cp_parser *parser)
   cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false);
   cp_parser_nested_name_specifier_opt (parser,
/*typename_keyword_p=*/true,
-   /*check_dependency_p=*/false,
+  /*check_dependency_p=*/true,
/*type_p=*/true,
/*is_declaration=*/false);
 
@@ -30987,7 +30987,7 @@ cp_parser_type_requirement (cp_parser *parser)
   cp_lexer_consume_token (parser->lexer);
   type = cp_parser_template_id (parser,
 /*template_keyword_p=*/true,
-/*check_dependency=*/false,
+   /*check_dependency_p=*/true,
 /*tag_type=*/none_type,
 /*is_declaration=*/false);
   type = make_typename_type (parser->scope, type, typename_type,
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires35.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-requires35.C
new file mode 100644
index 000..1dad931c01a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires35.C
@@ -0,0 +1,28 @@
+// PR c++/110927
+// { dg-do compile { target c++20 } }
+
+template
+struct A {
+  template struct B { using type = B; };
+
+  template using type = U;
+};
+
+template<> struct A { };
+
+template
+concept C1 = requires { typename A::template B::type; };
+
+template
+concept C2 = requires { typename A::template B; };
+
+template
+concept C3 = requires { typename A::template type; };
+
+static_assert(C1);
+static_assert(C2);
+static_assert(C3);
+
+static_assert(!C1);
+static_assert(!C2);
+static_assert(!C3);
-- 
2.42.0.rc0.25.ga82fb66fed



[PATCH] c++: recognize in-class var tmpl partial spec [PR71954]

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

-- >8 --

This makes us recognize variable template partial specializations
defined directly inside the class body.  It seems to suffice to call
check_explicit_specialization when we see a static TEMPLATE_ID_EXPR data
member, which sets SET_DECL_TEMPLATE_SPECIALIZATION and which we
otherwise don't call (for out-of-class partial specializations we call
it from from grokvardecl which is used only for out-of-class definitions).
We also need to make finish_member_template_decl return NULL_TREE for
such partial specializations (matching its behavior class template
partial specializations) so that its caller doesn't try to call
finish_member_declaration on it.

PR c++/71954

gcc/cp/ChangeLog:

* decl.cc (grokdeclarator): Use 'dname' instead of
'unqualified_id' when building the VAR_DECL for a static data
member.  Call check_explicit_specialization for a
TEMPLATE_ID_EXPR such member.
* pt.cc (finish_member_template_decl): Return NULL_TREE
instead of 'decl' when DECL_TEMPLATE_SPECIALIZATION is not
set.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1y/var-templ84.C: New test.
* g++.dg/cpp1y/var-templ84a.C: New test.
---
 gcc/cp/decl.cc| 11 ++-
 gcc/cp/pt.cc  |  2 +-
 gcc/testsuite/g++.dg/cpp1y/var-templ84.C  | 12 
 gcc/testsuite/g++.dg/cpp1y/var-templ84a.C | 19 +++
 4 files changed, 42 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/var-templ84.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/var-templ84a.C

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 9fe3a0b98fd..2b3fb313166 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -14440,7 +14440,16 @@ grokdeclarator (const cp_declarator *declarator,
/* C++ allows static class members.  All other work
   for this is done by grokfield.  */
decl = build_lang_decl_loc (id_loc, VAR_DECL,
-   unqualified_id, type);
+   dname, type);
+   if (unqualified_id
+   && TREE_CODE (unqualified_id) == TEMPLATE_ID_EXPR)
+ {
+   decl = check_explicit_specialization (unqualified_id, decl,
+ template_count,
+ concept_p * 8);
+   if (decl == error_mark_node)
+ return error_mark_node;
+ }
set_linkage_for_static_data_member (decl);
if (concept_p)
  error_at (declspecs->locations[ds_concept],
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 2706fa619bf..a4809f034dc 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -314,7 +314,7 @@ finish_member_template_decl (tree decl)
  return DECL_TI_TEMPLATE (decl);
}
   else
-   return decl;
+   return NULL_TREE;
 }
   else
 error_at (DECL_SOURCE_LOCATION (decl),
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ84.C 
b/gcc/testsuite/g++.dg/cpp1y/var-templ84.C
new file mode 100644
index 000..39c2a0dc0cc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/var-templ84.C
@@ -0,0 +1,12 @@
+// PR c++/71954
+// { dg-do compile { target c++14 } }
+
+struct A {
+  template static const int var = 0;
+  template static const int var = 1;
+  template static const int var = 2;
+};
+
+static_assert(A::var == 0, "");
+static_assert(A::var == 1, "");
+static_assert(A::var == 2, "");
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ84a.C 
b/gcc/testsuite/g++.dg/cpp1y/var-templ84a.C
new file mode 100644
index 000..4aa3a2a7245
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/var-templ84a.C
@@ -0,0 +1,19 @@
+// PR c++/71954
+// A version of var-templ84.C where the partial specializations depend on
+// outer template parameters.
+// { dg-do compile { target c++14 } }
+
+template
+struct A {
+  template static const int var = 0;
+  template static const int var = 1;
+  template static const int var = 2;
+};
+
+static_assert(A::var == 0, "");
+static_assert(A::var == 1, "");
+static_assert(A::var == 2, "");
+
+static_assert(A::var == 0, "");
+static_assert(A::var == 0, "");
+static_assert(A::var == 0, "");
-- 
2.42.0.rc0.25.ga82fb66fed



[PATCH] c++: bogus warning w/ deduction guide in anon ns [PR106604]

2023-08-10 Thread Patrick Palka via Gcc-patches
Booststrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk and perhaps 13?

-- >8 --

We shouldn't issue a "declared static but never defined" warning
for a deduction guide (declared in an anonymous namespace).

PR c++/106604

gcc/cp/ChangeLog:

* decl.cc (wrapup_namespace_globals): Don't issue a
-Wunused-function warning for a deduction guide.

gcc/testsuite/ChangeLog:

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

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 792ab330dd0..9fe3a0b98fd 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -856,6 +856,7 @@ wrapup_namespace_globals ()
  && !TREE_PUBLIC (decl)
  && !DECL_ARTIFICIAL (decl)
  && !DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION (decl)
+ && !deduction_guide_p (decl)
  && !warning_suppressed_p (decl, OPT_Wunused_function))
warning_at (DECL_SOURCE_LOCATION (decl),
OPT_Wunused_function,
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction116.C 
b/gcc/testsuite/g++.dg/cpp1z/class-deduction116.C
new file mode 100644
index 000..00f6d5fef41
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction116.C
@@ -0,0 +1,8 @@
+// PR c++/106604
+// { dg-do compile { target c++17 } }
+// { dg-additional-options "-Wunused-function" }
+
+namespace {
+  template struct A { A(...); };
+  A(bool) -> A; // { dg-bogus "never defined" }
+}
-- 
2.42.0.rc0.25.ga82fb66fed



Re: [PATCH] c++: bogus warning w/ deduction guide in anon ns [PR106604]

2023-08-10 Thread Patrick Palka via Gcc-patches
On Thu, 10 Aug 2023, Jason Merrill wrote:

> On 8/10/23 12:09, Patrick Palka wrote:
> > Booststrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > trunk and perhaps 13?
> > 
> > -- >8 --
> > 
> > We shouldn't issue a "declared static but never defined" warning
> > for a deduction guide (declared in an anonymous namespace).
> > 
> > PR c++/106604
> > 
> > gcc/cp/ChangeLog:
> > 
> > * decl.cc (wrapup_namespace_globals): Don't issue a
> > -Wunused-function warning for a deduction guide.
> 
> Maybe instead of special casing this here we could set DECL_INITIAL on
> deduction guides so they look defined?

That seems to work, but it requires some tweaks in duplicate_decls to keep
saying "declared" instead of "defined" when diagnosing a deduction guide
redeclaration.  I'm not sure which approach is preferable?

-- >8 --

gcc/cp/ChangeLog:

* decl.cc (duplicate_decls): When diagnosing a redeclared
deduction guide, ensure we say "declared" instead of "defined".
(redeclaration_error_message): Move up deduction guide tests.
(grokfndecl): Set DECL_INITIAL to void_node for a deduction
guide.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/class-deduction116.C: New test.
---
 gcc/cp/decl.cc| 23 +++
 .../g++.dg/cpp1z/class-deduction116.C |  5 
 2 files changed, 19 insertions(+), 9 deletions(-)

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 2b3fb313166..70dcff7aa8c 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -2025,7 +2025,9 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, 
bool was_hidden)
  error_at (newdecl_loc, errmsg, newdecl);
  if (DECL_NAME (olddecl) != NULL_TREE)
inform (olddecl_loc,
-   (DECL_INITIAL (olddecl) && namespace_bindings_p ())
+   (DECL_INITIAL (olddecl)
+&& !deduction_guide_p (olddecl)
+&& namespace_bindings_p ())
? G_("%q#D previously defined here")
: G_("%q#D previously declared here"), olddecl);
  return error_mark_node;
@@ -3271,6 +3273,10 @@ redeclaration_error_message (tree newdecl, tree olddecl)
   /* We'll complain about linkage mismatches in
 warn_extern_redeclared_static.  */
 
+  if (deduction_guide_p (olddecl)
+ && deduction_guide_p (newdecl))
+   return G_("deduction guide %q+D redeclared");
+
   /* Defining the same name twice is no good.  */
   if (decl_defined_p (olddecl)
  && decl_defined_p (newdecl))
@@ -3298,10 +3304,6 @@ redeclaration_error_message (tree newdecl, tree olddecl)
}
}
 
-  if (deduction_guide_p (olddecl)
- && deduction_guide_p (newdecl))
-   return G_("deduction guide %q+D redeclared");
-
   /* [class.compare.default]: A definition of a comparison operator as
 defaulted that appears in a class shall be the first declaration of
 that function.  */
@@ -3330,6 +3332,10 @@ redeclaration_error_message (tree newdecl, tree olddecl)
   if (DECL_TEMPLATE_RESULT (newdecl) == DECL_TEMPLATE_RESULT (olddecl))
return NULL;
 
+  if (deduction_guide_p (olddecl)
+ && deduction_guide_p (newdecl))
+   return G_("deduction guide %q+D redeclared");
+
   nt = DECL_TEMPLATE_RESULT (newdecl);
   if (DECL_TEMPLATE_INFO (nt))
nt = DECL_TEMPLATE_RESULT (template_for_substitution (nt));
@@ -3356,10 +3362,6 @@ redeclaration_error_message (tree newdecl, tree olddecl)
}
}
 
-  if (deduction_guide_p (olddecl)
- && deduction_guide_p (newdecl))
-   return G_("deduction guide %q+D redeclared");
-
   /* Core issue #226 (C++11):
 
If a friend function template declaration specifies a
@@ -10353,6 +10355,9 @@ grokfndecl (tree ctype,
   DECL_CXX_DESTRUCTOR_P (decl) = 1;
   DECL_NAME (decl) = dtor_identifier;
   break;
+case sfk_deduction_guide:
+  DECL_INITIAL (decl) = void_node;
+  break;
 default:
   break;
 }
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction116.C 
b/gcc/testsuite/g++.dg/cpp1z/class-deduction116.C
new file mode 100644
index 000..00f6d5fef41
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction116.C
@@ -0,0 +1,8 @@
+// PR c++/106604
+// { dg-do compile { target c++17 } }
+// { dg-additional-options "-Wunused-function" }
+
+namespace {
+  template struct A { A(...); };
+  A(bool) -> A; // { dg-bogus "never defined" }
+}
-- 
2.42.0.rc1


> 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/cpp1z/class-deduction116.C: New test.
> > ---
> >   gcc/cp/decl.cc  | 1 +
> >   gcc/testsuite/g++.dg/cpp1z/class-deduction116.C | 8 
> >   2 files changed, 9 insertions(+)
> >   create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction116.C
> > 
> > diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> > index 792ab330dd

Re: [PATCH] c++: improve debug_tree for templated types/decls

2023-08-10 Thread Patrick Palka via Gcc-patches
On Tue, 8 Aug 2023, Jason Merrill wrote:

> On 7/31/23 20:34, Patrick Palka wrote:
> > Tested on x86_64-pc-linux-gnu, does this look OK for trunk?
> > 
> > -- >8 --
> > 
> > gcc/cp/ChangeLog:
> > 
> > * ptree.cc (cxx_print_decl): Check for DECL_LANG_SPECIFIC and
> > TS_DECL_COMMON only when necessary.  Print DECL_TEMPLATE_INFO
> > for all decls that have it, not just VAR_DECL or FUNCTION_DECL.
> > Also print DECL_USE_TEMPLATE.
> > (cxx_print_type): Print TYPE_TEMPLATE_INFO.
> > : Don't print TYPE_TI_ARGS
> > anymore.
> > : Print TEMPLATE_TYPE_PARM_INDEX
> > instead of printing the index, level and original level
> > individually.
> > ---
> >   gcc/cp/ptree.cc | 32 +---
> >   1 file changed, 17 insertions(+), 15 deletions(-)
> > 
> > diff --git a/gcc/cp/ptree.cc b/gcc/cp/ptree.cc
> > index 33af7b81f58..13306fc8762 100644
> > --- a/gcc/cp/ptree.cc
> > +++ b/gcc/cp/ptree.cc
> > @@ -38,10 +38,6 @@ cxx_print_decl (FILE *file, tree node, int indent)
> > return;
> >   }
> >   -  if (!CODE_CONTAINS_STRUCT (TREE_CODE (node), TS_DECL_COMMON)
> > -  || !DECL_LANG_SPECIFIC (node))
> > -return;
> > -
> > if (TREE_CODE (node) == FUNCTION_DECL)
> >   {
> > int flags = TFF_DECL_SPECIFIERS|TFF_RETURN_TYPE
> > @@ -106,7 +102,10 @@ cxx_print_decl (FILE *file, tree node, int indent)
> > need_indent = false;
> >   }
> >   -  if (DECL_EXTERNAL (node) && DECL_NOT_REALLY_EXTERN (node))
> > +  if (CODE_CONTAINS_STRUCT (TREE_CODE (node), TS_DECL_COMMON)
> > +  && DECL_LANG_SPECIFIC (node)
> > +  && DECL_EXTERNAL (node)
> > +  && DECL_NOT_REALLY_EXTERN (node))
> >   {
> > if (need_indent)
> > indent_to (file, indent + 3);
> > @@ -115,6 +114,7 @@ cxx_print_decl (FILE *file, tree node, int indent)
> >   }
> >   if (TREE_CODE (node) == FUNCTION_DECL
> > +  && DECL_LANG_SPECIFIC (node)
> > && DECL_PENDING_INLINE_INFO (node))
> >   {
> > if (need_indent)
> > @@ -124,27 +124,29 @@ cxx_print_decl (FILE *file, tree node, int indent)
> > need_indent = false;
> >   }
> > -  if (VAR_OR_FUNCTION_DECL_P (node)
> > +  if (DECL_LANG_SPECIFIC (node)
> 
> Hmm, won't this crash on a non-COMMON decl?

Oops yes, I overlooked that DECL_LANG_SPECIFIC requires DECL_COMMON.  So
we should just move the early exit test down a bit.

> 
> > && DECL_TEMPLATE_INFO (node))

We also need to constrain the kinds of decls that we test
DECL_TEMPLATE_INFO on according to template_info_decl_check.

-- >8 --

Subject: [PATCH] c++: improve debug_tree for templated types/decls

gcc/cp/ChangeLog:

* ptree.cc (cxx_print_decl): Check for DECL_LANG_SPECIFIC and
TS_DECL_COMMON only when necessary.  Print DECL_TEMPLATE_INFO
for all decls that have it, not just VAR_DECL or FUNCTION_DECL.
Also print DECL_USE_TEMPLATE.
(cxx_print_type): Print TYPE_TEMPLATE_INFO.
: Don't print TYPE_TI_ARGS
anymore.
: Print TEMPLATE_TYPE_PARM_INDEX
instead of printing the index, level and original level
individually.
---
 gcc/cp/ptree.cc | 34 --
 1 file changed, 20 insertions(+), 14 deletions(-)

diff --git a/gcc/cp/ptree.cc b/gcc/cp/ptree.cc
index 33af7b81f58..b4001486701 100644
--- a/gcc/cp/ptree.cc
+++ b/gcc/cp/ptree.cc
@@ -38,10 +38,6 @@ cxx_print_decl (FILE *file, tree node, int indent)
   return;
 }
 
-  if (!CODE_CONTAINS_STRUCT (TREE_CODE (node), TS_DECL_COMMON)
-  || !DECL_LANG_SPECIFIC (node))
-return;
-
   if (TREE_CODE (node) == FUNCTION_DECL)
 {
   int flags = TFF_DECL_SPECIFIERS|TFF_RETURN_TYPE
@@ -106,6 +102,10 @@ cxx_print_decl (FILE *file, tree node, int indent)
   need_indent = false;
 }
 
+  if (!CODE_CONTAINS_STRUCT (TREE_CODE (node), TS_DECL_COMMON)
+  || !DECL_LANG_SPECIFIC (node))
+return;
+
   if (DECL_EXTERNAL (node) && DECL_NOT_REALLY_EXTERN (node))
 {
   if (need_indent)
@@ -124,27 +124,33 @@ cxx_print_decl (FILE *file, tree node, int indent)
   need_indent = false;
 }
   
-  if (VAR_OR_FUNCTION_DECL_P (node)
+  if ((VAR_OR_FUNCTION_DECL_P (node)
+   || TREE_CODE (node) == FIELD_DECL
+   || TREE_CODE (node) == TYPE_DECL
+   || TREE_CODE (node) == CONCEPT_DECL
+   || TREE_CODE (node) == TEMPLATE_DECL)
   && DECL_TEMPLATE_INFO (node))
-print_node (file, "template-info", DECL_TEMPLATE_INFO (node),
-   indent + 4);
+{
+  print_node (file, "template-info", DECL_TEMPLATE_INFO (node),
+ indent + 4);
+  indent_to (file, indent + 3);
+  fprintf (file, " use_template=%d", DECL_USE_TEMPLATE (node));
+}
 }
 
 void
 cxx_print_type (FILE *file, tree node, int indent)
 {
+  if (TYPE_LANG_SPECIFIC (node)
+  && TYPE_TEMPLATE_INFO (node))
+print_node (file, "template-info", TYPE_TEMPLATE_INFO (node), indent + 4);
+
   switch (TREE_CODE (node))
 {
 

Re: [PATCH] c++: bogus warning w/ deduction guide in anon ns [PR106604]

2023-08-11 Thread Patrick Palka via Gcc-patches
On Thu, 10 Aug 2023, Jason Merrill wrote:

> On 8/10/23 16:40, Patrick Palka wrote:
> > On Thu, 10 Aug 2023, Jason Merrill wrote:
> > 
> > > On 8/10/23 12:09, Patrick Palka wrote:
> > > > Booststrapped and regtested on x86_64-pc-linux-gnu, does this look OK
> > > > for
> > > > trunk and perhaps 13?
> > > > 
> > > > -- >8 --
> > > > 
> > > > We shouldn't issue a "declared static but never defined" warning
> > > > for a deduction guide (declared in an anonymous namespace).
> > > > 
> > > > PR c++/106604
> > > > 
> > > > gcc/cp/ChangeLog:
> > > > 
> > > > * decl.cc (wrapup_namespace_globals): Don't issue a
> > > > -Wunused-function warning for a deduction guide.
> > > 
> > > Maybe instead of special casing this here we could set DECL_INITIAL on
> > > deduction guides so they look defined?
> > 
> > That seems to work, but it requires some tweaks in duplicate_decls to keep
> > saying "declared" instead of "defined" when diagnosing a deduction guide
> > redeclaration.  I'm not sure which approach is preferable?
> 
> I'm not sure it matters which we say; the restriction that you can't repeat a
> deduction guide makes it more like a definition anyway (even if [basic.def]
> disagrees).  Is the diagnostic worse apart from that word?

Ah, makes sense.  So we can also remove the special case for them in the
redeclaration checking code after we give them a dummy DECL_INITIAL.
Like so?

Here's a before/after for the diagnostic with the below patch:

Before

src/gcc/testsuite/g++.dg/cpp1z/class-deduction74.C:11:1: error: deduction guide 
‘S()-> S’ redeclared
   11 | S() -> S; // { dg-error "redefinition" }
  | ^
src/gcc/testsuite/g++.dg/cpp1z/class-deduction74.C:10:1: note: ‘S()-> S’ 
previously declared here
   10 | S() -> S; // { dg-message "previously defined here|old 
declaration" }
  | ^

After

src/gcc/testsuite/g++.dg/cpp1z/class-deduction74.C:11:1: error: redefinition of 
‘S()-> S’
   11 | S() -> S; // { dg-error "redefinition" }
  | ^
src/gcc/testsuite/g++.dg/cpp1z/class-deduction74.C:10:1: note: ‘S()-> S’ 
previously defined here
   10 | S() -> S; // { dg-message "previously defined here|old 
declaration" }
  | ^

-- >8 --

Subject: [PATCH] c++: bogus warning w/ deduction guide in anon ns [PR106604]

Here we're unintentionally issuing a "declared static but never defined"
warning for a deduction guide declared in an anonymous namespace.
This patch fixes this by giving deduction guides a dummy DECL_INITIAL,
which suppresses the warning and also allows us to simplify redeclaration
checking for them.

Co-authored-by: Jason Merrill 

PR c++/106604

gcc/cp/ChangeLog:

* decl.cc (redeclaration_error_message): Remove special handling
for deduction guides.
(grokfndecl): Give deduction guides a dummy DECL_INITIAL.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/class-deduction74.C: Expect "defined" instead
of "declared" in diagnostics for a repeated deduction guide.
* g++.dg/cpp1z/class-deduction116.C: New test.
---
 gcc/cp/decl.cc  | 14 ++
 gcc/testsuite/g++.dg/cpp1z/class-deduction116.C |  8 
 gcc/testsuite/g++.dg/cpp1z/class-deduction74.C  | 14 +++---
 3 files changed, 21 insertions(+), 15 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction116.C

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 792ab330dd0..3ada5516c58 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -3297,10 +3297,6 @@ redeclaration_error_message (tree newdecl, tree olddecl)
}
}
 
-  if (deduction_guide_p (olddecl)
- && deduction_guide_p (newdecl))
-   return G_("deduction guide %q+D redeclared");
-
   /* [class.compare.default]: A definition of a comparison operator as
 defaulted that appears in a class shall be the first declaration of
 that function.  */
@@ -3355,10 +3351,6 @@ redeclaration_error_message (tree newdecl, tree olddecl)
}
}
 
-  if (deduction_guide_p (olddecl)
- && deduction_guide_p (newdecl))
-   return G_("deduction guide %q+D redeclared");
-
   /* Core issue #226 (C++11):
 
If a friend function template declaration specifies a
@@ -10352,6 +10344,12 @@ grokfndecl (tree ctype,
   DECL_CXX_DESTRUCTOR_P (decl) = 1;
   DECL_NAME (decl) = dtor_identifier;
   break;
+case sfk_deduction_guide:
+  /* Give deduction guides a definition even though they don't really
+have one: the restriction that you can't repeat a deduction guide
+makes them more like a definition anyway.  */
+  DECL_INITIAL (decl) = void_node;
+  break;
 default:
   break;
 }
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction116.C 
b/gcc/testsuite/g++.dg/cpp1z/class-deduction116.C
new file mode 100644
index 000..00f6d5fef41
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction116.C
@@ -0,0 +1,8 @@
+// PR c++/10660

[PATCH] tree-pretty-print: delimit TREE_VEC with braces

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

-- >8 --

This makes the generic pretty printer print braces around a TREE_VEC
like we do for CONSTRUCTOR.  This should improve readability of nested
TREE_VECs in particular.

gcc/ChangeLog:

* tree-pretty-print.cc (dump_generic_node) :
Delimit output with braces.
---
 gcc/tree-pretty-print.cc | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/gcc/tree-pretty-print.cc b/gcc/tree-pretty-print.cc
index 51a213529d1..579037b32c2 100644
--- a/gcc/tree-pretty-print.cc
+++ b/gcc/tree-pretty-print.cc
@@ -1900,6 +1900,7 @@ dump_generic_node (pretty_printer *pp, tree node, int 
spc, dump_flags_t flags,
 case TREE_VEC:
   {
size_t i;
+   pp_left_brace (pp);
if (TREE_VEC_LENGTH (node) > 0)
  {
size_t len = TREE_VEC_LENGTH (node);
@@ -1913,6 +1914,7 @@ dump_generic_node (pretty_printer *pp, tree node, int 
spc, dump_flags_t flags,
dump_generic_node (pp, TREE_VEC_ELT (node, len - 1), spc,
   flags, false);
  }
+   pp_right_brace (pp);
   }
   break;
 
-- 
2.42.0.rc1



Re: [PATCH] libstdc++: Implement P2770R0 changes to join_view / join_with_view

2023-08-16 Thread Patrick Palka via Gcc-patches
On Mon, Apr 17, 2023 at 9:39 AM Patrick Palka  wrote:
>
> This C++23 paper fixes a bug in these views when adapting a certain kind
> of non-forward range, and we treat it as a DR against C++20.
>
> Tested on x86_64-pc-linux-gnu, does this look OK for GCC 13?  This
> is an ABI change for join_view so it'd be unsuitable for backporting
> later I think :(

Ping, does this look OK for trunk?

>
> libstdc++-v3/ChangeLog:
>
> * include/bits/regex.h (regex_iterator::iterator_concept):
> Define for C++20 as per P2770R0.
> (regex_token_iterator::iterator_concept): Likewise.
> * include/std/ranges (__detail::__as_lvalue): Define.
> (join_view::_Iterator): Befriend join_view.
> (join_view::_Iterator::_M_satisfy): Use _M_get_outer
> instead of _M_outer.
> (join_view::_Iterator::_M_get_outer): Define.
> (join_view::_Iterator::_Iterator): Split constructor taking
> _Parent argument into two as per P2770R0.  Remove constraint on
> default constructor.
> (join_view::_Iterator::_M_outer): Make this data member present
> only when the underlying range is forward.
> (join_view::_Iterator::operator++): Use _M_get_outer instead of
> _M_outer.
> (join_view::_Iterator::operator--): Use __as_lvalue helper.
> (join_view::_Iterator::operator==): Adjust constraints as per
> P2770R0.
> (join_view::_Sentinel::__equal): Use _M_get_outer instead of
> _M_outer.
> (join_view::_M_outer): New data member when the underlying range
> is non-forward.
> (join_view::begin): Adjust definition as per P2770R0.
> (join_view::end): Likewise.
> (join_with_view::_M_outer_it): New data member when the
> underlying range is non-forward.
> (join_with_view::begin): Adjust definition as per P2770R0.
> (join_with_view::end): Likewise.
> (join_with_view::_Iterator::_M_outer_it): Make this data member
> present only when the underlying range is forward.
> (join_with_view::_Iterator::_M_get_outer): Define.
> (join_with_view::_Iterator::_Iterator): Split constructor
> taking _Parent argument into two as per P2770R0.  Remove
> constraint on default constructor.
> (join_with_view::_Iterator::_M_update_inner): Adjust definition
> as per P2770R0.
> (join_with_view::_Iterator::_M_get_inner): Likewise.
> (join_with_view::_Iterator::_M_satisfy): Adjust calls to
> _M_get_inner.  Use _M_get_outer instead of _M_outer_it.
> (join_with_view::_Iterator::operator==): Adjust constraints
> as per P2770R0.
> (join_with_view::_Sentinel::operator==): Use _M_get_outer
> instead of _M_outer_it.
> * testsuite/std/ranges/adaptors/p2770r0.cc: New test.
> ---
>  libstdc++-v3/include/bits/regex.h |   6 +
>  libstdc++-v3/include/std/ranges   | 190 +-
>  .../testsuite/std/ranges/adaptors/p2770r0.cc  | 110 ++
>  3 files changed, 257 insertions(+), 49 deletions(-)
>  create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/p2770r0.cc
>
> diff --git a/libstdc++-v3/include/bits/regex.h 
> b/libstdc++-v3/include/bits/regex.h
> index 26ac6a21c31..2d306868721 100644
> --- a/libstdc++-v3/include/bits/regex.h
> +++ b/libstdc++-v3/include/bits/regex.h
> @@ -2740,6 +2740,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>typedef const value_type*  pointer;
>typedef const value_type&  reference;
>typedef std::forward_iterator_tag  iterator_category;
> +#if __cplusplus > 201703L
> +  typedef std::input_iterator_tagiterator_concept;
> +#endif
>
>/**
> * @brief Provides a singular iterator, useful for indicating
> @@ -2869,6 +2872,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>typedef const value_type*pointer;
>typedef const value_type&reference;
>typedef std::forward_iterator_tagiterator_category;
> +#if __cplusplus > 201703L
> +  typedef std::input_iterator_tag  iterator_concept;
> +#endif
>
>  public:
>/**
> diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
> index 283d757faa4..ddcf50cc93e 100644
> --- a/libstdc++-v3/include/std/ranges
> +++ b/libstdc++-v3/include/std/ranges
> @@ -2705,6 +2705,14 @@ namespace views::__adaptor
>  inline constexpr _DropWhile drop_while;
>} // namespace views
>
> +  namespace __detail
> +  {
> +template
> +  constexpr _Tp&
> +  __as_lvalue(_Tp&& __t)
> +  { return static_cast<_Tp&>(__t); }
> +  } // namespace __detail
> +
>template
>  requires view<_Vp> && input_range>
>  class join_view : public view_interface>
> @@ -2767,6 +2775,8 @@ namespace views::__adaptor
>   using _Parent = __detail::__maybe_const_t<_Const, join_view>;
> 

Re: [PATCH 1/2] libstdc++: Convert _RangeAdaptorClosure into a CRTP class [PR108827]

2023-08-16 Thread Patrick Palka via Gcc-patches
On Sun, Apr 16, 2023 at 11:24 PM Patrick Palka  wrote:
>
> On Fri, 14 Apr 2023, Patrick Palka wrote:
>
> > Using the CRTP idiom for this base class avoids bloating the size of a
> > pipeline when adding distinct empty range adaptor closure objects to it,
> > as detailed in section 4.1 of P2387R3.
> >
> > But it means we can no longer define its operator| overloads as hidden
> > friends, since each instantiation of _RangeAdaptorClosure would then
> > introduce its own logically different hidden friends.  So for example
> > during overload resolution for the outer pipe operator in
> >
> >  :x | (views::reverse | views::join)
> >
> > we'd have to consider 6 different hidden operator| friends:
> >
> >   2 from _RangeAdaptorClosure<_Reverse>
> >   2 from _RangeAdaptorClosure<_Join>
> >   2 from _RangeAdaptorClosure<_Pipe<_Reverse, _Join>>
> >
> > which is wasteful and can even cause hard errors in some cases.  So we
> > instead define the operator| overloads at namespace scope in an isolated
> > namespace.
>
> On second thought, since this doesn't fix a bug or add new functionality
> it seems more like GCC 14 material.  The size reduction is nice but it's
> probably not a big deal in practice since adaptor pipelines are usually
> very transient objects that don't get passed around as function
> arguments etc.

Ping, does this look OK for trunk?

>
> But perhaps the second patch implementing range_adaptor_closure would be
> desirable for GCC 13?  I'll post an updated standalone version of that
> patch for separate consideration.
>
> >
> >   PR libstdc++/108827
> >
> > libstdc++-v3/ChangeLog:
> >
> >   * include/std/ranges (__adaptor::_RangeAdaptorClosure): Move ...
> >   (__adaptor::__closure::_RangeAdaptorClosure): ... here and turn
> >   it into a CRTP class template.  Move hidden operator| friends
> >   into namespace scope and adjust their constraints.  Add a
> >   using-declaration for this at __adaptor::_RangeAdaptorClosure.
> >   (__closure::__is_range_adaptor_closure_fn): Define.
> >   (__closure::__is_range_adaptor_closure): Define.
> >   (__adaptor::_Partial): Adjust use of _RangeAdaptorClosure.
> >   (__adaptor::_Pipe): Likewise.
> >   (views::_All): Likewise.
> >   (views::_Join): Likewise.
> >   (views::_Common): Likewise.
> >   (views::_Reverse): Likewise.
> >   (views::_Elements): Likewise.
> >   (views::_Adjacent): Likewise.
> >   (views::_AsRvalue): Likewise.
> >   (views::_Enumerate): Likewise.
> >   (views::_AsConst): Likewise.
> >   * testsuite/std/ranges/adaptors/all.cc: Reintroduce
> >   static_assert expecting that adding empty range adaptor
> >   closure objects to a pipeline doesn't increase the size of a
> >   pipeline.
> > ---
> >  libstdc++-v3/include/std/ranges   | 69 +++
> >  .../testsuite/std/ranges/adaptors/all.cc  |  7 --
> >  2 files changed, 42 insertions(+), 34 deletions(-)
> >
> > diff --git a/libstdc++-v3/include/std/ranges 
> > b/libstdc++-v3/include/std/ranges
> > index 283d757faa4..531ec6f68b3 100644
> > --- a/libstdc++-v3/include/std/ranges
> > +++ b/libstdc++-v3/include/std/ranges
> > @@ -872,30 +872,45 @@ namespace views::__adaptor
> >template
> >  struct _Pipe;
> >
> > -  // The base class of every range adaptor closure.
> > -  //
> > -  // The derived class should define the optional static data member
> > -  // _S_has_simple_call_op to true if the behavior of this adaptor is
> > -  // independent of the constness/value category of the adaptor object.
> > -  struct _RangeAdaptorClosure
> > +  namespace __closure
> >{
> > +// The base class of every range adaptor closure.
> > +//
> > +// The derived class should define the optional static data member
> > +// _S_has_simple_call_op to true if the behavior of this adaptor is
> > +// independent of the constness/value category of the adaptor object.
> > +template
> > +  struct _RangeAdaptorClosure
> > +  { };
> > +
> > +template
> > +  requires (!same_as<_Tp, _RangeAdaptorClosure<_Up>>)
> > +  void __is_range_adaptor_closure_fn
> > + (const _Tp&, const _RangeAdaptorClosure<_Up>&); // not defined
> > +
> > +template
> > +  concept __is_range_adaptor_closure
> > + = requires (_Tp __t) { __closure::__is_range_adaptor_closure_fn(__t, 
> > __t); };
> > +
> >  // range | adaptor is equivalent to adaptor(range).
> >  template
> > -  requires derived_from, _RangeAdaptorClosure>
> > +  requires __is_range_adaptor_closure<_Self>
> >   && __adaptor_invocable<_Self, _Range>
> > -  friend constexpr auto
> > +  constexpr auto
> >operator|(_Range&& __r, _Self&& __self)
> >{ return std::forward<_Self>(__self)(std::forward<_Range>(__r)); }
> >
> >  // Compose the adaptors __lhs and __rhs into a pipeline, returning
> >  // another range adaptor closure object.
> >  template
> > -  require

Re: [PATCH] libstdc++: Make __max_size_type and __max_diff_type structural

2023-08-16 Thread Patrick Palka via Gcc-patches
On Mon, Apr 24, 2023 at 12:23 PM Patrick Palka  wrote:
>
> This patch makes these integer-class type structural types by changing
> their private data members into public ones, which allows them to be
> used as NTTP types.  I'm not sure if this is required by the standard
> but it seems handy.
>
> Tested on x86_64-pc-linux-gnu, does this look OK for trunk?

Ping

>
> libstdc++-v3/ChangeLog:
>
> * include/bits/max_size_type.h (__max_size_type::_M_val): Make
> public instead of private.
> (__max_size_type::_M_msb): Likewise.
> (__max_diff_type::_M_rep): Likewise.
> * testsuite/std/ranges/iota/max_size_type.cc: Verify
> __max_diff_type and __max_size_type are structural.
> ---
>  libstdc++-v3/include/bits/max_size_type.h   | 4 ++--
>  libstdc++-v3/testsuite/std/ranges/iota/max_size_type.cc | 7 +++
>  2 files changed, 9 insertions(+), 2 deletions(-)
>
> diff --git a/libstdc++-v3/include/bits/max_size_type.h 
> b/libstdc++-v3/include/bits/max_size_type.h
> index 4796135d073..d6705bbe4c8 100644
> --- a/libstdc++-v3/include/bits/max_size_type.h
> +++ b/libstdc++-v3/include/bits/max_size_type.h
> @@ -423,10 +423,11 @@ namespace ranges
>using __rep = unsigned long long;
>  #endif
>static constexpr size_t _S_rep_bits = sizeof(__rep) * __CHAR_BIT__;
> -private:
> +
>__rep _M_val = 0;
>unsigned _M_msb:1 = 0;
>
> +private:
>constexpr explicit
>__max_size_type(__rep __val, int __msb) noexcept
> : _M_val(__val), _M_msb(__msb)
> @@ -750,7 +751,6 @@ namespace ranges
>{ return !(__l < __r); }
>  #endif
>
> -private:
>__max_size_type _M_rep = 0;
>
>friend class __max_size_type;
> diff --git a/libstdc++-v3/testsuite/std/ranges/iota/max_size_type.cc 
> b/libstdc++-v3/testsuite/std/ranges/iota/max_size_type.cc
> index 985acd5a803..9afd05d5acf 100644
> --- a/libstdc++-v3/testsuite/std/ranges/iota/max_size_type.cc
> +++ b/libstdc++-v3/testsuite/std/ranges/iota/max_size_type.cc
> @@ -400,6 +400,13 @@ static_assert(max_diff_t(max_size_t(1)
>  << (numeric_limits::digits-1))
>   == numeric_limits::min());
>
> +// Verify that the types are structural types and can therefore be used
> +// as NTTP types.
> +template struct Su { static_assert(V*V == V+132); };
> +template struct Ss { static_assert(V*V == V+132); };
> +template struct Su<12>;
> +template struct Ss<12>;
> +
>  int
>  main()
>  {
> --
> 2.40.0.374.g7580f92ffa
>



[PATCH] c++: refine CWG 2369 satisfaction vs non-dep convs [PR99599]

2023-08-21 Thread Patrick Palka via Gcc-patches
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look like
a reasonable approach?  I didn't observe any compile time/memory impact
of this change.

-- >8 --

As described in detail in the PR, CWG 2369 has the surprising
consequence of introducing constraint recursion in seemingly valid and
innocent code.

This patch attempts to fix this surpising behavior for the majority
of problematic use cases.  Rather than checking satisfaction before
_all_ non-dependent conversions, as specified by the CWG issue,
this patch makes us first check "safe" non-dependent conversions,
then satisfaction, then followed by "unsafe" non-dependent conversions.
In this case, a conversion is "safe" if computing it is guaranteed
to not induce template instantiation.  This patch heuristically
determines "safety" by checking for a constructor template or conversion
function template in the (class) parm or arg types respectively.
If neither type has such a member, then computing the conversion
should not induce instantiation (modulo satisfaction checking of
non-template constructor and conversion functions I suppose).

PR c++/99599

gcc/cp/ChangeLog:

* config-lang.in (gtfiles): Add search.cc.
* pt.cc (check_non_deducible_conversions): Add bool parameter
passed down to check_non_deducible_conversion.
(fn_type_unification): Call check_non_deducible_conversions
an extra time before satisfaction with noninst_only_p=true.
(check_non_deducible_conversion): Add bool parameter controlling
whether to compute only conversions that are guaranteed to
not induce template instantiation.
* search.cc (conversions_cache): Define.
(lookup_conversions): Use it to cache the lookup.  Improve cache
rate by considering TYPE_MAIN_VARIANT of the type.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts-nondep4.C: New test.
* g++.dg/cpp2a/concepts-nondep4a.C: New test.
---
 gcc/cp/config-lang.in |  1 +
 gcc/cp/pt.cc  | 66 +--
 gcc/cp/search.cc  | 14 +++-
 gcc/testsuite/g++.dg/cpp2a/concepts-nondep4.C | 21 ++
 .../g++.dg/cpp2a/concepts-nondep4a.C  | 30 +
 5 files changed, 125 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-nondep4.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-nondep4a.C

diff --git a/gcc/cp/config-lang.in b/gcc/cp/config-lang.in
index a6c7883cc24..e34c392d208 100644
--- a/gcc/cp/config-lang.in
+++ b/gcc/cp/config-lang.in
@@ -52,6 +52,7 @@ gtfiles="\
 \$(srcdir)/cp/name-lookup.cc \
 \$(srcdir)/cp/parser.cc \$(srcdir)/cp/pt.cc \
 \$(srcdir)/cp/rtti.cc \
+\$(srcdir)/cp/search.cc \
 \$(srcdir)/cp/semantics.cc \
 \$(srcdir)/cp/tree.cc \$(srcdir)/cp/typeck2.cc \
 \$(srcdir)/cp/vtable-class-hierarchy.cc \
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index a4809f034dc..c761b73b771 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -151,7 +151,7 @@ static tree get_partial_spec_bindings (tree, tree, tree);
 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, unification_kind_t, int,
-  struct conversion **, bool);
+  struct conversion **, bool, bool);
 static int maybe_adjust_types_for_deduction (tree, unification_kind_t,
 tree*, tree*, tree);
 static int type_unification_real (tree, tree, tree, const tree *,
@@ -22315,7 +22315,8 @@ pack_deducible_p (tree parm, tree fn)
 static int
 check_non_deducible_conversions (tree parms, const tree *args, unsigned nargs,
 tree fn, unification_kind_t strict, int flags,
-struct conversion **convs, bool explain_p)
+struct conversion **convs, bool explain_p,
+bool noninst_only_p)
 {
   /* Non-constructor methods need to leave a conversion for 'this', which
  isn't included in nargs here.  */
@@ -22351,7 +22352,7 @@ check_non_deducible_conversions (tree parms, const tree 
*args, unsigned nargs,
  int lflags = conv_flags (ia, nargs, fn, arg, flags);
 
  if (check_non_deducible_conversion (parm, arg, strict, lflags,
- conv_p, explain_p))
+ conv_p, explain_p, 
noninst_only_p))
return 1;
}
 
@@ -22651,6 +22652,16 @@ fn_type_unification (tree fn,
 
  deduced:
 
+  /* As a refinement of CWG2369, check first and foremost non-dependent
+ conversions that we know are not going to induce template instantiation
+ (PR99599).  */
+  if (strict == DEDUCE_CALL
+  && incomplete
+  && check_non_deducible_conversions (parms, args, nargs, fn, strict,

Re: [committed] libstdc++: Optimize std::to_array for trivial types [PR110167]

2023-06-19 Thread Patrick Palka via Gcc-patches
On Fri, 9 Jun 2023, Jonathan Wakely via Libstdc++ wrote:

> Tested powerpc64le-linux. Pushed to trunk.
> 
> This makes sense to backport after some soak time on trunk.
> 
> -- >8 --
> 
> As reported in PR libstdc++/110167, std::to_array compiles extremely
> slowly for very large arrays. It needs to instantiate a very large
> specialization of std::index_sequence and then create a very large
> aggregate initializer from the pack expansion. For trivial types we can
> simply default-initialize the std::array and then use memcpy to copy the
> values. For non-trivial types we need to use the existing
> implementation, despite the compilation cost.
> 
> As also noted in the PR, using a generic lambda instead of the
> __to_array helper compiles faster since gcc-13. It also produces
> slightly smaller code at -O1, due to additional inlining. The code at
> -Os, -O2 and -O3 seems to be the same. This new implementation requires
> __cpp_generic_lambdas >= 201707L (i.e. P0428R2) but that is supported
> since Clang 10 and since Intel icc 2021.5.0 (and since GCC 10.1).
> 
> libstdc++-v3/ChangeLog:
> 
>   PR libstdc++/110167
>   * include/std/array (to_array): Initialize arrays of trivial
>   types using memcpy. For non-trivial types, use lambda
>   expressions instead of a separate helper function.
>   (__to_array): Remove.
>   * testsuite/23_containers/array/creation/110167.cc: New test.
> ---
>  libstdc++-v3/include/std/array| 53 +--
>  .../23_containers/array/creation/110167.cc| 14 +
>  2 files changed, 51 insertions(+), 16 deletions(-)
>  create mode 100644 
> libstdc++-v3/testsuite/23_containers/array/creation/110167.cc
> 
> diff --git a/libstdc++-v3/include/std/array b/libstdc++-v3/include/std/array
> index 70280c1beeb..b791d86ddb2 100644
> --- a/libstdc++-v3/include/std/array
> +++ b/libstdc++-v3/include/std/array
> @@ -414,19 +414,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>return std::move(std::get<_Int>(__arr));
>  }
>  
> -#if __cplusplus > 201703L
> +#if __cplusplus >= 202002L && __cpp_generic_lambdas >= 201707L
>  #define __cpp_lib_to_array 201907L
> -
> -  template
> -constexpr array, sizeof...(_Idx)>
> -__to_array(_Tp (&__a)[sizeof...(_Idx)], index_sequence<_Idx...>)
> -{
> -  if constexpr (_Move)
> - return {{std::move(__a[_Idx])...}};
> -  else
> - return {{__a[_Idx]...}};
> -}
> -
>template
>  [[nodiscard]]
>  constexpr array, _Nm>
> @@ -436,8 +425,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>static_assert(!is_array_v<_Tp>);
>static_assert(is_constructible_v<_Tp, _Tp&>);
>if constexpr (is_constructible_v<_Tp, _Tp&>)
> - return __to_array(__a, make_index_sequence<_Nm>{});
> -  __builtin_unreachable(); // FIXME: see PR c++/91388
> + {
> +   if constexpr (is_trivial_v<_Tp> && _Nm != 0)

redundant _Nm != 0 test?

> + {
> +   array, _Nm> __arr;
> +   if (!__is_constant_evaluated() && _Nm != 0)
> + __builtin_memcpy(__arr.data(), __a, sizeof(__a));
> +   else
> + for (size_t __i = 0; __i < _Nm; ++__i)
> +   __arr._M_elems[__i] = __a[__i];
> +   return __arr;
> + }
> +   else
> + return [&__a](index_sequence<_Idx...>) {
> +   return array, _Nm>{{ __a[_Idx]... }};
> + }(make_index_sequence<_Nm>{});
> + }
> +  else
> + __builtin_unreachable(); // FIXME: see PR c++/91388
>  }
>  
>template
> @@ -449,8 +454,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>static_assert(!is_array_v<_Tp>);
>static_assert(is_move_constructible_v<_Tp>);
>if constexpr (is_move_constructible_v<_Tp>)
> - return __to_array<1>(__a, make_index_sequence<_Nm>{});
> -  __builtin_unreachable(); // FIXME: see PR c++/91388
> + {
> +   if constexpr (is_trivial_v<_Tp>)
> + {
> +   array, _Nm> __arr;
> +   if (!__is_constant_evaluated() && _Nm != 0)
> + __builtin_memcpy(__arr.data(), __a, sizeof(__a));
> +   else
> + for (size_t __i = 0; __i < _Nm; ++__i)
> +   __arr._M_elems[__i] = std::move(__a[__i]);

IIUC this std::move is unnecessary for trivial arrays?

> +   return __arr;
> + }
> +   else
> + return [&__a](index_sequence<_Idx...>) {
> +   return array, _Nm>{{ std::move(__a[_Idx])... }};
> + }(make_index_sequence<_Nm>{});
> + }
> +  else
> + __builtin_unreachable(); // FIXME: see PR c++/91388
>  }
>  #endif // C++20
>  
> diff --git a/libstdc++-v3/testsuite/23_containers/array/creation/110167.cc 
> b/libstdc++-v3/testsuite/23_containers/array/creation/110167.cc
> new file mode 100644
> index 000..c2aecc911bd
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/23_containers/array/creation/110167.cc
> @@ -0,0 +1,14 @@
> +// { dg-options "-std=gnu++20" }
> +// { dg-do compile { target c++20 } }
> +
> +// PR lib

Re: [PATCH 1/2] c++: implement __remove_pointer built-in trait

2023-06-20 Thread Patrick Palka via Gcc-patches
On Sat, 17 Jun 2023, Ken Matsui via Gcc-patches wrote:

> Hi,
> 
> I conducted a benchmark for remove_pointer as well as is_object. Just
> like the is_object benchmark, here is the benchmark code:
> 
> https://github.com/ken-matsui/gcc-benches/blob/main/remove_pointer_benchmark.cc
> 
> On my computer, using the gcc HEAD of this patch for a release build,
> the patch with -DUSE_BUILTIN took 8.7% less time and used 4.3-4.9%
> less memory on average compared to not using it. Although the
> performance improvement was not as significant as with is_object, the
> benchmark demonstrated that the compilation was consistently more
> efficient.

Thanks for the benchmark.  The improvement is lesser than I expected,
but that might be because the benchmark is "biased":

  template 
  struct Instantiator : Instantiator {
  static_assert(!std::is_pointer_v>);
  };

This only invokes remove_pointer_t on the non-pointer type Instantiator,
and so the benchmark doesn't factor in the performance of the trait when
invoked on pointer types, and traits typically will have different
performance characteristics depending on the kind of type it's given.

To more holistically assess the real-world performance of the trait the
benchmark should also consider pointer types and maybe also cv-qualified
types (given that the original implementation is in terms of
__remove_cv_t and thus performance of the original implementation may be
sensitive to cv-qualification).  So we should probably uniformly
benchmark these classes of types, via doing e.g.:

  static_assert(!std::is_pointer_v>);
  static_assert(!std::is_pointer_v>);
  static_assert(!std::is_pointer_v>);
  static_assert(!std::is_pointer_v>);

(We could consider other kinds of types too, e.g. reference types and
integral types, but it seems clear based on the implementations being
benchmarked that performance won't be sensitive to reference-ness
or integral-ness.)

> 
> Sincerely,
> Ken Matsui
> 
> On Thu, Jun 15, 2023 at 5:22 AM Ken Matsui  wrote:
> >
> > This patch implements built-in trait for std::remove_pointer.
> >
> > gcc/cp/ChangeLog:
> >
> > * cp-trait.def: Define __remove_pointer.
> > * semantics.cc (finish_trait_type): Handle CPTK_REMOVE_POINTER.
> >
> > gcc/testsuite/ChangeLog:
> >
> > * g++.dg/ext/has-builtin-1.C: Test existence of __remove_pointer.
> > * g++.dg/ext/remove_pointer.C: New test.
> >
> > Signed-off-by: Ken Matsui 
> > ---
> >  gcc/cp/cp-trait.def   |  1 +
> >  gcc/cp/semantics.cc   |  4 ++
> >  gcc/testsuite/g++.dg/ext/has-builtin-1.C  |  3 ++
> >  gcc/testsuite/g++.dg/ext/remove_pointer.C | 51 +++
> >  4 files changed, 59 insertions(+)
> >  create mode 100644 gcc/testsuite/g++.dg/ext/remove_pointer.C
> >
> > diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
> > index 8b7fece0cc8..07823e55579 100644
> > --- a/gcc/cp/cp-trait.def
> > +++ b/gcc/cp/cp-trait.def
> > @@ -90,6 +90,7 @@ DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
> >  DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
> >  DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
> >  DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
> > +DEFTRAIT_TYPE (REMOVE_POINTER, "__remove_pointer", 1)
> >  DEFTRAIT_TYPE (UNDERLYING_TYPE,  "__underlying_type", 1)
> >  DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
> >
> > diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> > index 8fb47fd179e..885c7a6fb64 100644
> > --- a/gcc/cp/semantics.cc
> > +++ b/gcc/cp/semantics.cc
> > @@ -12373,6 +12373,10 @@ finish_trait_type (cp_trait_kind kind, tree type1, 
> > tree type2,
> >if (TYPE_REF_P (type1))
> > type1 = TREE_TYPE (type1);
> >return cv_unqualified (type1);
> > +case CPTK_REMOVE_POINTER:
> > +  if (TYPE_PTR_P (type1))
> > +type1 = TREE_TYPE (type1);
> > +  return type1;

Maybe add a newline before the 'case' to visually separate it from the
previous 'case'?  LGTM otherwise, thanks!

> >
> >  case CPTK_TYPE_PACK_ELEMENT:
> >return finish_type_pack_element (type1, type2, complain);
> > diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C 
> > b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> > index f343e153e56..e21e0a95509 100644
> > --- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> > +++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> > @@ -146,3 +146,6 @@
> >  #if !__has_builtin (__remove_cvref)
> >  # error "__has_builtin (__remove_cvref) failed"
> >  #endif
> > +#if !__has_builtin (__remove_pointer)
> > +# error "__has_builtin (__remove_pointer) failed"
> > +#endif
> > diff --git a/gcc/testsuite/g++.dg/ext/remove_pointer.C 
> > b/gcc/testsuite/g++.dg/ext/remove_pointer.C
> > new file mode 100644
> > index 000..7b13db93950
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/ext/remove_pointer.C
> > @@ -0,0 +1,51 @@
> > +// { dg-do compile { target c++11 } }
> > +
> > +#define SA(X) static_assert((X),#X)
> > +
> > +SA(__is_same(__remove_point

Re: [PATCH v7 0/6] c++, libstdc++: get std::is_object to dispatch to new built-in traits

2023-06-20 Thread Patrick Palka via Gcc-patches
On Thu, 15 Jun 2023, Ken Matsui via Libstdc++ wrote:

> Hi,
> 
> For those curious about the performance improvements of this patch, I
> conducted a benchmark that instantiates 256k specializations of
> is_object_v based on Patrick's code. You can find the benchmark code
> at this link:
> 
> https://github.com/ken-matsui/gcc-benches/blob/main/is_object_benchmark.cc
> 
> On my computer, using the gcc HEAD of this patch for a release build,
> the patch with -DUSE_BUILTIN took 64% less time and used 44-47% less
> memory compared to not using it.

That's more like it :D  Though the benchmark should also invoke the
trait on non-object types too, e.g. Instantiator& or Instantiator(int).

> 
> Sincerely,
> Ken Matsui
> 
> On Mon, Jun 12, 2023 at 3:49 PM Ken Matsui  wrote:
> >
> > Hi,
> >
> > This patch series gets std::is_object to dispatch to built-in traits and
> > implements the following built-in traits, on which std::object depends.
> >
> > * __is_reference
> > * __is_function
> > * __is_void
> >
> > std::is_object was depending on them with disjunction and negation.
> >
> > __not_<__or_, is_reference<_Tp>, is_void<_Tp>>>::type
> >
> > Therefore, this patch uses them directly instead of implementing an 
> > additional
> > built-in trait __is_object, which makes the compiler slightly bigger and
> > slower.
> >
> > __bool_constant > __is_void(_Tp))>
> >
> > This would instantiate only __bool_constant and 
> > __bool_constant,
> > which can be mostly shared. That is, the purpose of built-in traits is
> > considered as achieved.
> >
> > Changes in v7
> >
> > * Removed an unnecessary new line.
> >
> > Ken Matsui (6):
> >   c++: implement __is_reference built-in trait
> >   libstdc++: use new built-in trait __is_reference for std::is_reference
> >   c++: implement __is_function built-in trait
> >   libstdc++: use new built-in trait __is_function for std::is_function
> >   c++, libstdc++: implement __is_void built-in trait
> >   libstdc++: make std::is_object dispatch to new built-in traits
> >
> >  gcc/cp/constraint.cc  |  9 +++
> >  gcc/cp/cp-trait.def   |  3 +
> >  gcc/cp/semantics.cc   | 12 
> >  gcc/testsuite/g++.dg/ext/has-builtin-1.C  |  9 +++
> >  gcc/testsuite/g++.dg/ext/is_function.C| 58 +++
> >  gcc/testsuite/g++.dg/ext/is_reference.C   | 34 +++
> >  gcc/testsuite/g++.dg/ext/is_void.C| 35 +++
> >  gcc/testsuite/g++.dg/tm/pr46567.C |  6 +-
> >  libstdc++-v3/include/bits/cpp_type_traits.h   | 15 -
> >  libstdc++-v3/include/debug/helper_functions.h |  5 +-
> >  libstdc++-v3/include/std/type_traits  | 51 
> >  11 files changed, 216 insertions(+), 21 deletions(-)
> >  create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C
> >  create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C
> >  create mode 100644 gcc/testsuite/g++.dg/ext/is_void.C
> >
> > --
> > 2.41.0
> >
> 
> 


Re: [PATCH v7 5/6] c++, libstdc++: implement __is_void built-in trait

2023-06-20 Thread Patrick Palka via Gcc-patches
On Mon, 12 Jun 2023, Ken Matsui via Libstdc++ wrote:

> This patch implements built-in trait for std::is_void. Since the new built-in
> name is __is_void, to avoid unintentional macro replacement, this patch also
> involves the removal of the existing __is_void in helper_functions.h and
> cpp_type_traits.h and renaming __is_void to is_void in the test file,
> pr46567.C.

Hmm, I suspect an __is_void built-in won't show an improvement over
the current is_void implementation in terms of four explicit specializations.
And given the __is_void name conflict in cpp_type_traits.h (which means
GCC trunk will reject older libstdc++ headers at least until we get
smarter about how we recognize built-ins), I'm leaning towards not
implementing an __is_void built-in for now.

In that case we should probably define a built-in for is_object since
we can no longer implement it solely in terms of other built-ins, and
fortunately the name __is_object seems to never have been used in
libstdc++ so we won't have to deal with any name conflicts unlike with
__is_void.

Jonathan, what do you think?

> 
> gcc/cp/ChangeLog:
> 
>   * cp-trait.def: Define __is_void.
>   * constraint.cc (diagnose_trait_expr): Handle CPTK_IS_VOID.
>   * semantics.cc (trait_expr_value): Likewise.
>   (finish_trait_expr): Likewise.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/tm/pr46567.C (__is_void): Rename to ...
>   (is_void): ... this.
>   * g++.dg/ext/has-builtin-1.C: Test existence of __is_void.
>   * g++.dg/ext/is_void.C: New test.
> 
> libstdc++-v3/ChangeLog:
> 
>   * include/debug/helper_functions.h (_DiffTraits): Stop using
>   __is_void.
>   * include/bits/cpp_type_traits.h (__is_void): Remove unused __is_void.
>   * include/std/type_traits (is_void_v): Use __is_void built-in
>   trait.
> 
> Signed-off-by: Ken Matsui 
> ---
>  gcc/cp/constraint.cc  |  3 ++
>  gcc/cp/cp-trait.def   |  1 +
>  gcc/cp/semantics.cc   |  4 +++
>  gcc/testsuite/g++.dg/ext/has-builtin-1.C  |  3 ++
>  gcc/testsuite/g++.dg/ext/is_void.C| 35 +++
>  gcc/testsuite/g++.dg/tm/pr46567.C |  6 ++--
>  libstdc++-v3/include/bits/cpp_type_traits.h   | 15 
>  libstdc++-v3/include/debug/helper_functions.h |  5 ++-
>  libstdc++-v3/include/std/type_traits  |  6 
>  9 files changed, 57 insertions(+), 21 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_void.C
> 
> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> index 927605c6cb7..e8cd98eb2c7 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -3757,6 +3757,9 @@ diagnose_trait_expr (tree expr, tree args)
>  case CPTK_IS_FUNCTION:
>inform (loc, "  %qT is not a function", t1);
>break;
> +case CPTK_IS_VOID:
> +  inform (loc, "  %qT is not a void type", t1);
> +  break;
>  case CPTK_IS_AGGREGATE:
>inform (loc, "  %qT is not an aggregate", t1);
>break;
> diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
> index 3cd3babc242..8e76668f6ed 100644
> --- a/gcc/cp/cp-trait.def
> +++ b/gcc/cp/cp-trait.def
> @@ -84,6 +84,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, 
> "__is_trivially_constructible", -1)
>  DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
>  DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
>  DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
> +DEFTRAIT_EXPR (IS_VOID, "__is_void", 1)
>  DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, 
> "__reference_constructs_from_temporary", 2)
>  DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, 
> "__reference_converts_from_temporary", 2)
>  /* FIXME Added space to avoid direct usage in GCC 13.  */
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index b976633645a..c4d44413dce 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -12075,6 +12075,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, 
> tree type2)
>  case CPTK_IS_FUNCTION:
>return type_code1 == FUNCTION_TYPE;
>  
> +case CPTK_IS_VOID:
> +  return VOID_TYPE_P (type1);
> +
>  case CPTK_IS_FINAL:
>return CLASS_TYPE_P (type1) && CLASSTYPE_FINAL (type1);
>  
> @@ -12297,6 +12300,7 @@ finish_trait_expr (location_t loc, cp_trait_kind 
> kind, tree type1, tree type2)
>  case CPTK_IS_SAME:
>  case CPTK_IS_REFERENCE:
>  case CPTK_IS_FUNCTION:
> +case CPTK_IS_VOID:
>break;
>  
>  case CPTK_IS_LAYOUT_COMPATIBLE:
> diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C 
> b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> index 90eb00ebf2d..b96cc9e6f50 100644
> --- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> +++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> @@ -152,3 +152,6 @@
>  #if !__has_builtin (__is_function)
>  # error "__has_builtin (__is_function) failed"
>  #endif
> +#if !__has_builtin (__is_void)
> +# error "__has_builtin (__is_void) failed"
> +#endif
> diff --git 

Re: [PATCH v7 4/6] libstdc++: use new built-in trait __is_function for std::is_function

2023-06-20 Thread Patrick Palka via Gcc-patches
On Mon, 12 Jun 2023, Ken Matsui via Libstdc++ wrote:

> This patch gets std::is_function to dispatch to new built-in trait
> __is_function.
> 
> libstdc++-v3/ChangeLog:
> 
>   * include/std/type_traits (is_function): Use __is_function built-in
>   trait.
>   (is_function_v): Likewise.

LGTM

> 
> Signed-off-by: Ken Matsui 
> ---
>  libstdc++-v3/include/std/type_traits | 13 +
>  1 file changed, 13 insertions(+)
> 
> diff --git a/libstdc++-v3/include/std/type_traits 
> b/libstdc++-v3/include/std/type_traits
> index 2a14df7e5f9..954b57518de 100644
> --- a/libstdc++-v3/include/std/type_traits
> +++ b/libstdc++-v3/include/std/type_traits
> @@ -594,6 +594,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>  { };
>  
>/// is_function
> +#if __has_builtin(__is_function)
> +  template
> +struct is_function
> +: public __bool_constant<__is_function(_Tp)>
> +{ };
> +#else
>template
>  struct is_function
>  : public __bool_constant::value> { };
> @@ -605,6 +611,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>template
>  struct is_function<_Tp&&>
>  : public false_type { };
> +#endif
>  
>  #define __cpp_lib_is_null_pointer 201309L
>  
> @@ -3197,8 +3204,14 @@ template 
>inline constexpr bool is_union_v = __is_union(_Tp);
>  template 
>inline constexpr bool is_class_v = __is_class(_Tp);
> +
> +#if __has_builtin(__is_function)
> +template 
> +  inline constexpr bool is_function_v = __is_function(_Tp);
> +#else
>  template 
>inline constexpr bool is_function_v = is_function<_Tp>::value;
> +#endif
>  
>  #if __has_builtin(__is_reference)
>  template 
> -- 
> 2.41.0
> 
> 



Re: [PATCH v7 3/6] c++: implement __is_function built-in trait

2023-06-20 Thread Patrick Palka via Gcc-patches
On Mon, 12 Jun 2023, Ken Matsui via Gcc-patches wrote:

> This patch implements built-in trait for std::is_function.
> 
> gcc/cp/ChangeLog:
> 
>   * cp-trait.def: Define __is_function.
>   * constraint.cc (diagnose_trait_expr): Handle CPTK_IS_FUNCTION.
>   * semantics.cc (trait_expr_value): Likewise.
>   (finish_trait_expr): Likewise.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/ext/has-builtin-1.C: Test existence of __is_function.
>   * g++.dg/ext/is_function.C: New test.

LGTM

> 
> Signed-off-by: Ken Matsui 
> ---
>  gcc/cp/constraint.cc |  3 ++
>  gcc/cp/cp-trait.def  |  1 +
>  gcc/cp/semantics.cc  |  4 ++
>  gcc/testsuite/g++.dg/ext/has-builtin-1.C |  3 ++
>  gcc/testsuite/g++.dg/ext/is_function.C   | 58 
>  5 files changed, 69 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C
> 
> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> index f6951ee2670..927605c6cb7 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -3754,6 +3754,9 @@ diagnose_trait_expr (tree expr, tree args)
>  case CPTK_IS_UNION:
>inform (loc, "  %qT is not a union", t1);
>break;
> +case CPTK_IS_FUNCTION:
> +  inform (loc, "  %qT is not a function", t1);
> +  break;
>  case CPTK_IS_AGGREGATE:
>inform (loc, "  %qT is not an aggregate", t1);
>break;
> diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
> index 1e3310cd682..3cd3babc242 100644
> --- a/gcc/cp/cp-trait.def
> +++ b/gcc/cp/cp-trait.def
> @@ -83,6 +83,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, 
> "__is_trivially_assignable", 2)
>  DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", 
> -1)
>  DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
>  DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
> +DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
>  DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, 
> "__reference_constructs_from_temporary", 2)
>  DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, 
> "__reference_converts_from_temporary", 2)
>  /* FIXME Added space to avoid direct usage in GCC 13.  */
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index 2f37bc353a1..b976633645a 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -12072,6 +12072,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, 
> tree type2)
>  case CPTK_IS_ENUM:
>return type_code1 == ENUMERAL_TYPE;
>  
> +case CPTK_IS_FUNCTION:
> +  return type_code1 == FUNCTION_TYPE;
> +
>  case CPTK_IS_FINAL:
>return CLASS_TYPE_P (type1) && CLASSTYPE_FINAL (type1);
>  
> @@ -12293,6 +12296,7 @@ finish_trait_expr (location_t loc, cp_trait_kind 
> kind, tree type1, tree type2)
>  case CPTK_IS_UNION:
>  case CPTK_IS_SAME:
>  case CPTK_IS_REFERENCE:
> +case CPTK_IS_FUNCTION:
>break;
>  
>  case CPTK_IS_LAYOUT_COMPATIBLE:
> diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C 
> b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> index b697673790c..90eb00ebf2d 100644
> --- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> +++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> @@ -149,3 +149,6 @@
>  #if !__has_builtin (__is_reference)
>  # error "__has_builtin (__is_reference) failed"
>  #endif
> +#if !__has_builtin (__is_function)
> +# error "__has_builtin (__is_function) failed"
> +#endif
> diff --git a/gcc/testsuite/g++.dg/ext/is_function.C 
> b/gcc/testsuite/g++.dg/ext/is_function.C
> new file mode 100644
> index 000..2e1594b12ad
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/ext/is_function.C
> @@ -0,0 +1,58 @@
> +// { dg-do compile { target c++11 } }
> +
> +#include 
> +
> +using namespace __gnu_test;
> +
> +#define SA(X) static_assert((X),#X)
> +#define SA_TEST_CATEGORY(TRAIT, TYPE, EXPECT)\
> +  SA(TRAIT(TYPE) == EXPECT); \
> +  SA(TRAIT(const TYPE) == EXPECT);   \
> +  SA(TRAIT(volatile TYPE) == EXPECT);\
> +  SA(TRAIT(const volatile TYPE) == EXPECT)
> +
> +struct A
> +{ void fn(); };
> +
> +template
> +struct AHolder { };
> +
> +template
> +struct AHolder
> +{ using type = U; };
> +
> +// Positive tests.
> +SA(__is_function(int (int)));
> +SA(__is_function(ClassType (ClassType)));
> +SA(__is_function(float (int, float, int[], int&)));
> +SA(__is_function(int (int, ...)));
> +SA(__is_function(bool (ClassType) const));
> +SA(__is_function(AHolder::type));
> +
> +void fn();
> +SA(__is_function(decltype(fn)));
> +
> +// Negative tests.
> +SA_TEST_CATEGORY(__is_function, int, false);
> +SA_TEST_CATEGORY(__is_function, int*, false);
> +SA_TEST_CATEGORY(__is_function, int&, false);
> +SA_TEST_CATEGORY(__is_function, void, false);
> +SA_TEST_CATEGORY(__is_function, void*, false);
> +SA_TEST_CATEGORY(__is_function, void**, false);
> +SA_TEST_CATEGORY(__is_function, std::nullptr_t, false);
> +
> +SA_TEST_CATEGORY(__is_function, Abst

Re: [PATCH v7 1/6] c++: implement __is_reference built-in trait

2023-06-20 Thread Patrick Palka via Gcc-patches
On Mon, 12 Jun 2023, Ken Matsui via Libstdc++ wrote:

> This patch implements built-in trait for std::is_reference.
> 
> gcc/cp/ChangeLog:
> 
>   * cp-trait.def: Define __is_reference.
>   * constraint.cc (diagnose_trait_expr): Handle CPTK_IS_REFERENCE.
>   * semantics.cc (trait_expr_value): Likewise.
>   (finish_trait_expr): Likewise.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/ext/has-builtin-1.C: Test existence of __is_reference.
>   * g++.dg/ext/is_reference.C: New test.

LGTM

> 
> Signed-off-by: Ken Matsui 
> ---
>  gcc/cp/constraint.cc |  3 +++
>  gcc/cp/cp-trait.def  |  1 +
>  gcc/cp/semantics.cc  |  4 +++
>  gcc/testsuite/g++.dg/ext/has-builtin-1.C |  3 +++
>  gcc/testsuite/g++.dg/ext/is_reference.C  | 34 
>  5 files changed, 45 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C
> 
> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> index 8cf0f2d0974..f6951ee2670 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -3705,6 +3705,9 @@ diagnose_trait_expr (tree expr, tree args)
>  case CPTK_HAS_VIRTUAL_DESTRUCTOR:
>inform (loc, "  %qT does not have a virtual destructor", t1);
>break;
> +case CPTK_IS_REFERENCE:
> +  inform (loc, "  %qT is not a reference", t1);
> +  break;
>  case CPTK_IS_ABSTRACT:
>inform (loc, "  %qT is not an abstract class", t1);
>break;
> diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
> index 8b7fece0cc8..1e3310cd682 100644
> --- a/gcc/cp/cp-trait.def
> +++ b/gcc/cp/cp-trait.def
> @@ -67,6 +67,7 @@ DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
>  DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
>  DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
>  DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
> +DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
>  DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
>  DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
>  DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index a2e74a5d2c7..2f37bc353a1 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -12075,6 +12075,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, 
> tree type2)
>  case CPTK_IS_FINAL:
>return CLASS_TYPE_P (type1) && CLASSTYPE_FINAL (type1);
>  
> +case CPTK_IS_REFERENCE:
> +  return type_code1 == REFERENCE_TYPE;
> +
>  case CPTK_IS_LAYOUT_COMPATIBLE:
>return layout_compatible_type_p (type1, type2);
>  
> @@ -12289,6 +12292,7 @@ finish_trait_expr (location_t loc, cp_trait_kind 
> kind, tree type1, tree type2)
>  case CPTK_IS_ENUM:
>  case CPTK_IS_UNION:
>  case CPTK_IS_SAME:
> +case CPTK_IS_REFERENCE:
>break;
>  
>  case CPTK_IS_LAYOUT_COMPATIBLE:
> diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C 
> b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> index f343e153e56..b697673790c 100644
> --- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> +++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> @@ -146,3 +146,6 @@
>  #if !__has_builtin (__remove_cvref)
>  # error "__has_builtin (__remove_cvref) failed"
>  #endif
> +#if !__has_builtin (__is_reference)
> +# error "__has_builtin (__is_reference) failed"
> +#endif
> diff --git a/gcc/testsuite/g++.dg/ext/is_reference.C 
> b/gcc/testsuite/g++.dg/ext/is_reference.C
> new file mode 100644
> index 000..b5ce4db7afd
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/ext/is_reference.C
> @@ -0,0 +1,34 @@
> +// { dg-do compile { target c++11 } }
> +
> +#include 
> +
> +using namespace __gnu_test;
> +
> +#define SA(X) static_assert((X),#X)
> +#define SA_TEST_CATEGORY(TRAIT, TYPE, EXPECT)\
> +  SA(TRAIT(TYPE) == EXPECT); \
> +  SA(TRAIT(const TYPE) == EXPECT);   \
> +  SA(TRAIT(volatile TYPE) == EXPECT);\
> +  SA(TRAIT(const volatile TYPE) == EXPECT)
> +
> +// Positive tests.
> +SA_TEST_CATEGORY(__is_reference, int&, true);
> +SA_TEST_CATEGORY(__is_reference, ClassType&, true);
> +SA(__is_reference(int(&)(int)));
> +SA_TEST_CATEGORY(__is_reference, int&&, true);
> +SA_TEST_CATEGORY(__is_reference, ClassType&&, true);
> +SA(__is_reference(int(&&)(int)));
> +SA_TEST_CATEGORY(__is_reference, IncompleteClass&, true);
> +
> +// Negative tests
> +SA_TEST_CATEGORY(__is_reference, void, false);
> +SA_TEST_CATEGORY(__is_reference, int*, false);
> +SA_TEST_CATEGORY(__is_reference, int[3], false);
> +SA(!__is_reference(int(int)));
> +SA(!__is_reference(int(*const)(int)));
> +SA(!__is_reference(int(*volatile)(int)));
> +SA(!__is_reference(int(*const volatile)(int)));
> +
> +// Sanity check.
> +SA_TEST_CATEGORY(__is_reference, ClassType, false);
> +SA_TEST_CATEGORY(__is_reference, IncompleteClass, false);
> -- 
> 2.41.0
> 
> 



Re: [PATCH v7 2/6] libstdc++: use new built-in trait __is_reference for std::is_reference

2023-06-20 Thread Patrick Palka via Gcc-patches
On Mon, 12 Jun 2023, Ken Matsui via Libstdc++ wrote:

> This patch gets std::is_reference to dispatch to new built-in trait
> __is_reference.
> 
> libstdc++-v3/ChangeLog:
> 
>   * include/std/type_traits (is_reference): Use __is_reference built-in
>   trait.
>   (is_reference_v): Likewise.

LGTM

> 
> Signed-off-by: Ken Matsui 
> ---
>  libstdc++-v3/include/std/type_traits | 14 ++
>  1 file changed, 14 insertions(+)
> 
> diff --git a/libstdc++-v3/include/std/type_traits 
> b/libstdc++-v3/include/std/type_traits
> index 0e7a9c9c7f3..2a14df7e5f9 100644
> --- a/libstdc++-v3/include/std/type_traits
> +++ b/libstdc++-v3/include/std/type_traits
> @@ -639,6 +639,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>// Composite type categories.
>  
>/// is_reference
> +#if __has_builtin(__is_reference)
> +  template
> +struct is_reference
> +: public __bool_constant<__is_reference(_Tp)>
> +{ };
> +#else
>template
>  struct is_reference
>  : public false_type
> @@ -653,6 +659,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>  struct is_reference<_Tp&&>
>  : public true_type
>  { };
> +#endif
>  
>/// is_arithmetic
>template
> @@ -3192,12 +3199,19 @@ template 
>inline constexpr bool is_class_v = __is_class(_Tp);
>  template 
>inline constexpr bool is_function_v = is_function<_Tp>::value;
> +
> +#if __has_builtin(__is_reference)
> +template 
> +  inline constexpr bool is_reference_v = __is_reference(_Tp);
> +#else
>  template 
>inline constexpr bool is_reference_v = false;
>  template 
>inline constexpr bool is_reference_v<_Tp&> = true;
>  template 
>inline constexpr bool is_reference_v<_Tp&&> = true;
> +#endif
> +
>  template 
>inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
>  template 
> -- 
> 2.41.0
> 
> 



Re: [PATCH 2/2] libstdc++: use new built-in trait __is_const

2023-06-20 Thread Patrick Palka via Gcc-patches
On Tue, 21 Mar 2023, Ken Matsui wrote:

> This patch lets libstdc++ use new built-in trait __is_const.
> 
> libstdc++-v3/ChangeLog:
> 
>   * include/std/type_traits (is_const): Use __is_const built-in trait.

We should also use it in is_const_v (likewise for the __is_array and
__is_volatile patches).

> ---
>  libstdc++-v3/include/std/type_traits | 7 +++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/libstdc++-v3/include/std/type_traits 
> b/libstdc++-v3/include/std/type_traits
> index 2bd607a8b8f..e77de828501 100644
> --- a/libstdc++-v3/include/std/type_traits
> +++ b/libstdc++-v3/include/std/type_traits
> @@ -764,6 +764,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>// Type properties.
>  
>/// is_const
> +#if __has_builtin(__is_const)
> +  template
> +struct is_const
> +: public __bool_constant<__is_const(_Tp)>
> +{ };
> +#else
>template
>  struct is_const
>  : public false_type { };
> @@ -771,6 +777,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>template
>  struct is_const<_Tp const>
>  : public true_type { };
> +#endif
>  
>/// is_volatile
>template
> -- 
> 2.40.0
> 
> 



[PATCH] c++: redundant targ coercion for var/alias tmpls

2023-06-21 Thread Patrick Palka via Gcc-patches
When stepping through the variable/alias template specialization code
paths, I noticed we perform template argument coercion twice: first from
instantiate_alias_template / finish_template_variable and again from
tsubst_decl (during instantiate_template).  It should suffice to perform
coercion once.

To that end patch elides this second coercion from tsubst_decl when
possible.  We can't get rid of it completely because we don't always
specialize a variable template from finish_template_variable: we could
also be doing so directly from instantiate_template during variable
template partial specialization selection, in which case the coercion
from tsubst_decl would be the first and only coercion.

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?  This reduces memory usage of range-v3's zip.cpp by ~0.5%.

gcc/cp/ChangeLog:

* pt.cc (tsubst_decl) : Call
coercion_template_parms only if DECL_TEMPLATE_SPECIALIZATION
is set.
---
 gcc/cp/pt.cc | 15 +++
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index be86051abad..dd10409ce18 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -15232,10 +15232,17 @@ tsubst_decl (tree t, tree args, tsubst_flags_t 
complain)
argvec = tsubst (DECL_TI_ARGS (t), args, complain, in_decl);
if (argvec != error_mark_node
&& PRIMARY_TEMPLATE_P (gen_tmpl)
-   && TMPL_ARGS_DEPTH (args) >= TMPL_ARGS_DEPTH (argvec))
- /* We're fully specializing a template declaration, so
-we need to coerce the innermost arguments corresponding to
-the template.  */
+   && TMPL_ARGS_DEPTH (args) >= TMPL_ARGS_DEPTH (argvec)
+   && DECL_TEMPLATE_SPECIALIZATION (t))
+ /* We're fully specializing an alias or variable template, so
+coerce the innermost arguments if necessary.  We expect
+instantiate_alias_template and finish_template_variable to
+already have done this relative to the primary template, in
+which case this coercion is unnecessary, but we can also
+get here when substituting a partial variable template
+specialization (directly from instantiate_template), in
+which case DECL_TEMPLATE_SPECIALIZATION is set and coercion
+is necessary.  */
  argvec = (coerce_template_parms
(DECL_TEMPLATE_PARMS (gen_tmpl),
 argvec, tmpl, complain));
-- 
2.41.0.113.g6640c2d06d



Re: [PATCH] c++: Fix ICE with parameter pack of decltype(auto) [PR103497]

2023-06-23 Thread Patrick Palka via Gcc-patches
Hi,

On Sat, 22 Apr 2023, Nathaniel Shead via Gcc-patches wrote:

> Bootstrapped and tested on x86_64-pc-linux-gnu.
> 
> -- 8< --
> 
> This patch raises an error early when the decltype(auto) specifier is
> used as a parameter of a function. This prevents any issues with an
> unexpected tree type later on when performing the call.

Thanks very much for the patch!  Some minor comments below.

> 
>   PR 103497

We should include the bug component name when referring to the PR in the
commit message (i.e. PR c++/103497) so that upon pushing the patch the
post-commit hook automatically adds a comment to the PR reffering to the
commit.  I could be wrong but AFAIK the hook only performs this when the
component name is included.

> 
> gcc/cp/ChangeLog:
> 
>   * parser.cc (cp_parser_simple_type_specifier): Add check for
>   decltype(auto) as function parameter.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/pr103497.C: New test.
> 
> Signed-off-by: Nathaniel Shead 
> ---
>  gcc/cp/parser.cc| 10 ++
>  gcc/testsuite/g++.dg/pr103497.C |  7 +++
>  2 files changed, 17 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/pr103497.C
> 
> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> index e5f032f2330..1415e07e152 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -19884,6 +19884,16 @@ cp_parser_simple_type_specifier (cp_parser* parser,
>&& cp_lexer_peek_nth_token (parser->lexer, 2)->type != CPP_SCOPE)
>  {
>type = saved_checks_value (token->u.tree_check_value);
> +  /* Within a function parameter declaration, decltype(auto) is always an
> +  error.  */
> +  if (parser->auto_is_implicit_function_template_parm_p
> +   && TREE_CODE (type) == TEMPLATE_TYPE_PARM

We could check is_auto (type) here instead, to avoid any confusion with
checking AUTO_IS_DECLTYPE for a non-auto TEMPLATE_TYPE_PARM.

> +   && AUTO_IS_DECLTYPE (type))
> + {
> +   error_at (token->location,
> + "cannot declare a parameter with %");
> +   type = error_mark_node;
> + }
>if (decl_specs)
>   {
> cp_parser_set_decl_spec_type (decl_specs, type,
> diff --git a/gcc/testsuite/g++.dg/pr103497.C b/gcc/testsuite/g++.dg/pr103497.C
> new file mode 100644
> index 000..bcd421c2907
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/pr103497.C
> @@ -0,0 +1,7 @@
> +// { dg-do compile { target c++14 } }
> +
> +void foo(decltype(auto)... args);  // { dg-error "parameter with 
> .decltype.auto..|no parameter packs" }

I noticed for

  void foo(decltype(auto) arg);

we already issue an identical error from grokdeclarator.  Perhaps we could
instead extend the error handling there to detect decltype(auto)... as well,
rather than adding new error handling in cp_parser_simple_type_specifier?

> +
> +int main() {
> +  foo();
> +}
> -- 
> 2.34.1
> 
> 



Re: [PATCH] c++: Report invalid id-expression in decltype [PR100482]

2023-06-23 Thread Patrick Palka via Gcc-patches
On Sun, 30 Apr 2023, Nathaniel Shead via Gcc-patches wrote:

> This patch ensures that any errors raised by finish_id_expression when
> parsing a decltype expression are properly reported, rather than
> potentially going ignored and causing invalid code to be accepted.
> 
> We can also now remove the separate check for templates without args as
> this is also checked for in finish_id_expression.
> 
>   PR 100482
> 
> gcc/cp/ChangeLog:
> 
>   * parser.cc (cp_parser_decltype_expr): Report errors raised by
>   finish_id_expression.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/pr100482.C: New test.

LGTM.  Some minor comments about the new testcase below:

> 
> Signed-off-by: Nathaniel Shead 
> ---
>  gcc/cp/parser.cc| 22 +++---
>  gcc/testsuite/g++.dg/pr100482.C | 11 +++
>  2 files changed, 22 insertions(+), 11 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/pr100482.C
> 
> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> index e5f032f2330..20ebcdc3cfd 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -16508,10 +16508,6 @@ cp_parser_decltype_expr (cp_parser *parser,
>   expr = cp_parser_lookup_name_simple (parser, expr,
>id_expr_start_token->location);
>  
> -  if (expr && TREE_CODE (expr) == TEMPLATE_DECL)
> - /* A template without args is not a complete id-expression.  */
> - expr = error_mark_node;
> -
>if (expr
>&& expr != error_mark_node
>&& TREE_CODE (expr) != TYPE_DECL
> @@ -16532,13 +16528,17 @@ cp_parser_decltype_expr (cp_parser *parser,
> &error_msg,
>  id_expr_start_token->location));
>  
> -  if (expr == error_mark_node)
> -/* We found an id-expression, but it was something that we
> -   should not have found. This is an error, not something
> -   we can recover from, so note that we found an
> -   id-expression and we'll recover as gracefully as
> -   possible.  */
> -id_expression_or_member_access_p = true;
> +   if (error_msg)
> + {
> +   /* We found an id-expression, but it was something that we
> +  should not have found. This is an error, not something
> +  we can recover from, so report the error we found and
> +  we'll recover as gracefully as possible.  */
> +   cp_parser_parse_definitely (parser);
> +   cp_parser_error (parser, error_msg);
> +   id_expression_or_member_access_p = true;
> +   return error_mark_node;
> + }
>  }
>  
>if (expr
> diff --git a/gcc/testsuite/g++.dg/pr100482.C b/gcc/testsuite/g++.dg/pr100482.C
> new file mode 100644
> index 000..dcf6722fda5
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/pr100482.C

We generally prefer to organize tests according to the language dialect
they apply to and the langugae construct that they're primarily testing.
In this case we could name the test e.g.

  gcc/testsuite/g++.dg/cpp0x/decltype-100482.C

> @@ -0,0 +1,11 @@
> +// { dg-do compile { target c++10 } }

We also usually mention the PR number in the test as a comment:

// PR c++/100482

One benefit of doing so is that the git alias 'git gcc-commit-mklog'
(https://gcc.gnu.org/gitwrite.html#vendor) will then automatically
include the PR number in the commit message template.

> +
> +namespace N {}
> +decltype(std) x;   // { dg-error "expected primary-expression" }
> +
> +struct S {};
> +decltype(S) y;  // { dg-error "argument to .decltype. must be an expression" 
> }
> +
> +template 
> +struct U {};
> +decltype(U) z;  // { dg-error "missing template arguments" }
> -- 
> 2.40.0
> 
> 



Re: [PATCH] c++: redundant targ coercion for var/alias tmpls

2023-06-23 Thread Patrick Palka via Gcc-patches
On Fri, 23 Jun 2023, Jason Merrill wrote:

> On 6/21/23 13:19, Patrick Palka wrote:
> > When stepping through the variable/alias template specialization code
> > paths, I noticed we perform template argument coercion twice: first from
> > instantiate_alias_template / finish_template_variable and again from
> > tsubst_decl (during instantiate_template).  It should suffice to perform
> > coercion once.
> > 
> > To that end patch elides this second coercion from tsubst_decl when
> > possible.  We can't get rid of it completely because we don't always
> > specialize a variable template from finish_template_variable: we could
> > also be doing so directly from instantiate_template during variable
> > template partial specialization selection, in which case the coercion
> > from tsubst_decl would be the first and only coercion.
> 
> Perhaps we should be coercing in lookup_template_variable rather than
> finish_template_variable?

Ah yes, there's a patch for that at
https://gcc.gnu.org/pipermail/gcc-patches/2023-May/617377.html :)

> It looks like we currently get to
> most_specialized_partial_spec with args that haven't yet been coerced to match
> the primary template.

The call to most_specialized_partial_spec from instantiate_template?
I believe the arguments should already have been coerced by the
caller, which is presumably always finish_template_variable.

So in that patch I also made instantiate_template use
build2 (TEMPLATE_ID_EXPR, ...) directly instead of calling
lookup_template_variable, to avoid an unnecessary double coercion.

> 
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > trunk?  This reduces memory usage of range-v3's zip.cpp by ~0.5%.
> > 
> > gcc/cp/ChangeLog:
> > 
> > * pt.cc (tsubst_decl) : Call
> > coercion_template_parms only if DECL_TEMPLATE_SPECIALIZATION
> > is set.
> > ---
> >   gcc/cp/pt.cc | 15 +++
> >   1 file changed, 11 insertions(+), 4 deletions(-)
> > 
> > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > index be86051abad..dd10409ce18 100644
> > --- a/gcc/cp/pt.cc
> > +++ b/gcc/cp/pt.cc
> > @@ -15232,10 +15232,17 @@ tsubst_decl (tree t, tree args, tsubst_flags_t
> > complain)
> > argvec = tsubst (DECL_TI_ARGS (t), args, complain, in_decl);
> > if (argvec != error_mark_node
> > && PRIMARY_TEMPLATE_P (gen_tmpl)
> > -   && TMPL_ARGS_DEPTH (args) >= TMPL_ARGS_DEPTH (argvec))
> > - /* We're fully specializing a template declaration, so
> > -we need to coerce the innermost arguments corresponding
> > to
> > -the template.  */
> > +   && TMPL_ARGS_DEPTH (args) >= TMPL_ARGS_DEPTH (argvec)
> > +   && DECL_TEMPLATE_SPECIALIZATION (t))
> > + /* We're fully specializing an alias or variable template,
> > so
> > +coerce the innermost arguments if necessary.  We expect
> > +instantiate_alias_template and finish_template_variable
> > to
> > +already have done this relative to the primary template,
> > in
> > +which case this coercion is unnecessary, but we can also
> > +get here when substituting a partial variable template
> > +specialization (directly from instantiate_template), in
> > +which case DECL_TEMPLATE_SPECIALIZATION is set and
> > coercion
> > +is necessary.  */
> >   argvec = (coerce_template_parms
> > (DECL_TEMPLATE_PARMS (gen_tmpl),
> >  argvec, tmpl, complain));
> 
> 



Re: [PATCH v2 1/3] c++: Track lifetimes in constant evaluation [PR70331, PR96630, PR98675]

2023-06-23 Thread Patrick Palka via Gcc-patches
On Wed, 29 Mar 2023, Nathaniel Shead via Gcc-patches wrote:

> This adds rudimentary lifetime tracking in C++ constexpr contexts,
> allowing the compiler to report errors with using values after their
> backing has gone out of scope. We don't yet handle other ways of ending
> lifetimes (e.g. explicit destructor calls).

Awesome!

> 
>   PR c++/96630
>   PR c++/98675
>   PR c++/70331
> 
> gcc/cp/ChangeLog:
> 
>   * constexpr.cc (constexpr_global_ctx::put_value): Mark value as
>   in lifetime.
>   (constexpr_global_ctx::remove_value): Mark value as expired.
>   (cxx_eval_call_expression): Remove comment that is no longer
>   applicable.
>   (non_const_var_error): Add check for expired values.
>   (cxx_eval_constant_expression): Add checks for expired values. Forget
>   local variables at end of bind expressions. Forget temporaries at end
>   of cleanup points.
>   * cp-tree.h (struct lang_decl_base): New flag to track expired values
>   in constant evaluation.
>   (DECL_EXPIRED_P): Access the new flag.
>   (SET_DECL_EXPIRED_P): Modify the new flag.
>   * module.cc (trees_out::lang_decl_bools): Write out the new flag.
>   (trees_in::lang_decl_bools): Read in the new flag.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp0x/constexpr-ice20.C: Update error raised by test.
>   * g++.dg/cpp1y/constexpr-lifetime1.C: New test.
>   * g++.dg/cpp1y/constexpr-lifetime2.C: New test.
>   * g++.dg/cpp1y/constexpr-lifetime3.C: New test.
>   * g++.dg/cpp1y/constexpr-lifetime4.C: New test.
>   * g++.dg/cpp1y/constexpr-lifetime5.C: New test.
> 
> Signed-off-by: Nathaniel Shead 
> ---
>  gcc/cp/constexpr.cc   | 69 +++
>  gcc/cp/cp-tree.h  | 10 ++-
>  gcc/cp/module.cc  |  2 +
>  gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C  |  2 +-
>  .../g++.dg/cpp1y/constexpr-lifetime1.C| 13 
>  .../g++.dg/cpp1y/constexpr-lifetime2.C| 20 ++
>  .../g++.dg/cpp1y/constexpr-lifetime3.C| 13 
>  .../g++.dg/cpp1y/constexpr-lifetime4.C| 11 +++
>  .../g++.dg/cpp1y/constexpr-lifetime5.C| 11 +++
>  9 files changed, 137 insertions(+), 14 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime1.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime2.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime3.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime4.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C
> 
> diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> index 3de60cfd0f8..bdbc12144a7 100644
> --- a/gcc/cp/constexpr.cc
> +++ b/gcc/cp/constexpr.cc
> @@ -1185,10 +1185,22 @@ public:
>void put_value (tree t, tree v)
>{
>  bool already_in_map = values.put (t, v);
> +if (!already_in_map && DECL_P (t))
> +  {
> + if (!DECL_LANG_SPECIFIC (t))
> +   retrofit_lang_decl (t);
> + if (DECL_LANG_SPECIFIC (t))
> +   SET_DECL_EXPIRED_P (t, false);
> +  }

Since this new flag would only be used only during constexpr evaluation,
could we instead use an on-the-side hash_set in constexpr_global_ctx for
tracking expired-ness?  That way we won't have to allocate a
DECL_LANG_SPECIFIC structure for decls that lack it, and won't have to
worry about the flag in other parts of the compiler.

>  if (!already_in_map && modifiable)
>modifiable->add (t);
>}
> -  void remove_value (tree t) { values.remove (t); }
> +  void remove_value (tree t)
> +  {
> +if (DECL_P (t) && DECL_LANG_SPECIFIC (t))
> +  SET_DECL_EXPIRED_P (t, true);
> +values.remove (t);
> +  }
>  };
>  
>  /* Helper class for constexpr_global_ctx.  In some cases we want to avoid
> @@ -3157,10 +3169,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, 
> tree t,
> for (tree save_expr : save_exprs)
>   ctx->global->remove_value (save_expr);
>  
> -   /* Remove the parms/result from the values map.  Is it worth
> -  bothering to do this when the map itself is only live for
> -  one constexpr evaluation?  If so, maybe also clear out
> -  other vars from call, maybe in BIND_EXPR handling?  */
> +   /* Remove the parms/result from the values map.  */
> ctx->global->remove_value (res);
> for (tree parm = parms; parm; parm = TREE_CHAIN (parm))
>   ctx->global->remove_value (parm);
> @@ -5708,6 +5717,13 @@ non_const_var_error (location_t loc, tree r, bool 
> fundef_p)
>   inform (DECL_SOURCE_LOCATION (r), "allocated here");
>return;
>  }
> +  if (DECL_EXPIRED_P (r))
> +{
> +  if (constexpr_error (loc, fundef_p, "accessing object outside its "
> +"lifetime"))
> + inform (DECL_SOURCE_LOCATION (r), "declared here");
> +  return;
> +}
>if (!constexpr_error (loc, fundef_p, "the value of 

Re: [PATCH v2 2/3] c++: Improve constexpr error for dangling local variables

2023-06-23 Thread Patrick Palka via Gcc-patches
On Wed, 29 Mar 2023, Nathaniel Shead via Gcc-patches wrote:

> Currently, when typeck discovers that a return statement will refer to a
> local variable it rewrites to return a null pointer. This causes the
> error messages for using the return value in a constant expression to be
> unhelpful, especially for reference return values.
> 
> This patch removes this "optimisation". Relying on this raises a warning
> by default and causes UB anyway, so there should be no issue in doing
> so. We also suppress additional warnings from later passes that detect
> this as a dangling pointer, since we've already indicated this anyway.

LGTM.  It seems the original motivation for returning a null pointer
here was to avoid issuing duplicate warnings
(https://gcc.gnu.org/legacy-ml/gcc-patches/2014-04/msg00269.html)
which your patch addresses.

> 
> gcc/cp/ChangeLog:
> 
>   * semantics.cc (finish_return_stmt): Suppress dangling pointer
> reporting on return statement if already reported.
>   * typeck.cc (check_return_expr): Don't set return expression to
> zero for dangling addresses.
> 
> gcc/testsuite/ChangeLog:
> 
> * g++.dg/cpp1y/constexpr-lifetime5.C: Test reported message is
> correct.
>   * g++.dg/warn/Wreturn-local-addr-6.C: Remove check for return
> value optimisation.
> 
> Signed-off-by: Nathaniel Shead 
> ---
>  gcc/cp/semantics.cc  | 5 -
>  gcc/cp/typeck.cc | 5 +++--
>  gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C | 4 ++--
>  gcc/testsuite/g++.dg/warn/Wreturn-local-addr-6.C | 3 ---
>  4 files changed, 9 insertions(+), 8 deletions(-)
> 
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index 87c2e8a7111..14b4b7f4ce1 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -1246,7 +1246,10 @@ finish_return_stmt (tree expr)
>  
>r = build_stmt (input_location, RETURN_EXPR, expr);
>if (no_warning)
> -suppress_warning (r, OPT_Wreturn_type);
> +{
> +  suppress_warning (r, OPT_Wreturn_type);
> +  suppress_warning (r, OPT_Wdangling_pointer_);
> +}
>r = maybe_cleanup_point_expr_void (r);
>r = add_stmt (r);
>  
> diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
> index afb956087ce..a7d642e2029 100644
> --- a/gcc/cp/typeck.cc
> +++ b/gcc/cp/typeck.cc
> @@ -11235,8 +11235,9 @@ check_return_expr (tree retval, bool *no_warning)
>else if (!processing_template_decl
>  && maybe_warn_about_returning_address_of_local (retval, loc)
>  && INDIRECT_TYPE_P (valtype))
> - retval = build2 (COMPOUND_EXPR, TREE_TYPE (retval), retval,
> -  build_zero_cst (TREE_TYPE (retval)));
> + /* Suppress the Wdangling-pointer warning in the return statement
> +that would otherwise occur.  */
> + *no_warning = true;
>  }
>  
>if (processing_template_decl)
> diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C 
> b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C
> index a4bc71d890a..ad3ef579f63 100644
> --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C
> +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C
> @@ -1,11 +1,11 @@
>  // { dg-do compile { target c++14 } }
>  // { dg-options "-Wno-return-local-addr" }
>  
> -constexpr const int& id(int x) { return x; }
> +constexpr const int& id(int x) { return x; }  // { dg-message "note: 
> declared here" }
>  
>  constexpr bool test() {
>const int& y = id(3);
>return y == 3;
>  }
>  
> -constexpr bool x = test();  // { dg-error "" }
> +constexpr bool x = test();  // { dg-error "accessing object outside its 
> lifetime" }
> diff --git a/gcc/testsuite/g++.dg/warn/Wreturn-local-addr-6.C 
> b/gcc/testsuite/g++.dg/warn/Wreturn-local-addr-6.C
> index fae8b7e766f..ec8e241d83e 100644
> --- a/gcc/testsuite/g++.dg/warn/Wreturn-local-addr-6.C
> +++ b/gcc/testsuite/g++.dg/warn/Wreturn-local-addr-6.C
> @@ -24,6 +24,3 @@ return_addr_local_as_intref (void)
>  
>return (const intptr_t&)a;   // { dg-warning "\\\[-Wreturn-local-addr]" } 
> */
>  }
> -
> -/* Verify that the return value has been replaced with zero:
> -  { dg-final { scan-tree-dump-times "return 0;" 2 "optimized" } } */
> -- 
> 2.34.1
> 
> 



Re: [PATCH v2 3/3] c++: Improve location information in constexpr evaluation

2023-06-23 Thread Patrick Palka via Gcc-patches
On Wed, 29 Mar 2023, Nathaniel Shead via Gcc-patches wrote:

> This patch caches the current expression's location information in the
> constexpr_global_ctx struct, which allows subexpressions that have lost
> location information to still provide accurate diagnostics. Also
> rewrites a number of 'error' calls as 'error_at' to provide more
> specific location information.
> 
> The primary effect of this change is that many errors within evaluation
> of a constexpr function will now point at the offending expression (with
> expansion tracing information) rather than just the outermost call.

This seems like a great improvement!

In other parts of the frontend, e.g. during substitution from
tsubst_expr or tsubst_copy_and_build, we do something similar by
setting/restoring input_location directly.  (We've since added the RAII
class iloc_sentinel for this.)  I wonder if that'd be preferable here?

> 
> gcc/cp/ChangeLog:
> 
>   * constexpr.cc (constexpr_global_ctx): New field for cached
>   tree location, defaulting to input_location.
>   (cxx_eval_internal_function): Fall back to ctx->global->loc
>   rather than input_location.
>   (modifying_const_object_error): Likewise.
>   (cxx_eval_dynamic_cast_fn): Likewise.
>   (eval_and_check_array_index): Likewise.
>   (cxx_eval_array_reference): Likewise.
>   (cxx_eval_bit_field_ref): Likewise.
>   (cxx_eval_component_reference): Likewise.
>   (cxx_eval_indirect_ref): Likewise.
>   (cxx_eval_store_expression): Likewise.
>   (cxx_eval_increment_expression): Likewise.
>   (cxx_eval_loop_expr): Likewise.
>   (cxx_eval_binary_expression): Likewise.
>   (cxx_eval_constant_expression): Cache location of trees for use
> in errors, and prefer it instead of input_location.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp0x/constexpr-48089.C: Updated diagnostic locations.
>   * g++.dg/cpp0x/constexpr-diag3.C: Likewise.
>   * g++.dg/cpp0x/constexpr-ice20.C: Likewise.
>   * g++.dg/cpp1y/constexpr-89481.C: Likewise.
>   * g++.dg/cpp1y/constexpr-lifetime1.C: Likewise.
>   * g++.dg/cpp1y/constexpr-lifetime2.C: Likewise.
>   * g++.dg/cpp1y/constexpr-lifetime3.C: Likewise.
>   * g++.dg/cpp1y/constexpr-lifetime4.C: Likewise.
>   * g++.dg/cpp1y/constexpr-lifetime5.C: Likewise.
>   * g++.dg/cpp1y/constexpr-union5.C: Likewise.
>   * g++.dg/cpp1y/pr68180.C: Likewise.
>   * g++.dg/cpp1z/constexpr-lambda6.C: Likewise.
>   * g++.dg/cpp2a/bit-cast11.C: Likewise.
>   * g++.dg/cpp2a/bit-cast12.C: Likewise.
>   * g++.dg/cpp2a/bit-cast14.C: Likewise.
>   * g++.dg/cpp2a/constexpr-98122.C: Likewise.
>   * g++.dg/cpp2a/constexpr-dynamic17.C: Likewise.
>   * g++.dg/cpp2a/constexpr-init1.C: Likewise.
>   * g++.dg/cpp2a/constexpr-new12.C: Likewise.
>   * g++.dg/cpp2a/constexpr-new3.C: Likewise.
>   * g++.dg/ext/constexpr-vla2.C: Likewise.
>   * g++.dg/ext/constexpr-vla3.C: Likewise.
>   * g++.dg/ubsan/pr63956.C: Likewise.
> 
> libstdc++/ChangeLog:
> 
>   * testsuite/25_algorithms/equal/constexpr_neg.cc: Updated
>   diagnostics locations.
> 
> Signed-off-by: Nathaniel Shead 
> ---
>  gcc/cp/constexpr.cc   | 83 +++
>  gcc/testsuite/g++.dg/cpp0x/constexpr-48089.C  | 10 +--
>  gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C  |  2 +-
>  gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C  |  4 +-
>  gcc/testsuite/g++.dg/cpp1y/constexpr-89481.C  |  3 +-
>  .../g++.dg/cpp1y/constexpr-lifetime1.C|  1 +
>  .../g++.dg/cpp1y/constexpr-lifetime2.C|  4 +-
>  .../g++.dg/cpp1y/constexpr-lifetime3.C|  4 +-
>  .../g++.dg/cpp1y/constexpr-lifetime4.C|  2 +-
>  .../g++.dg/cpp1y/constexpr-lifetime5.C|  4 +-
>  gcc/testsuite/g++.dg/cpp1y/constexpr-union5.C |  4 +-
>  gcc/testsuite/g++.dg/cpp1y/pr68180.C  |  4 +-
>  .../g++.dg/cpp1z/constexpr-lambda6.C  |  4 +-
>  gcc/testsuite/g++.dg/cpp2a/bit-cast11.C   | 10 +--
>  gcc/testsuite/g++.dg/cpp2a/bit-cast12.C   | 10 +--
>  gcc/testsuite/g++.dg/cpp2a/bit-cast14.C   | 14 ++--
>  gcc/testsuite/g++.dg/cpp2a/constexpr-98122.C  |  4 +-
>  .../g++.dg/cpp2a/constexpr-dynamic17.C|  5 +-
>  gcc/testsuite/g++.dg/cpp2a/constexpr-init1.C  |  5 +-
>  gcc/testsuite/g++.dg/cpp2a/constexpr-new12.C  |  6 +-
>  gcc/testsuite/g++.dg/cpp2a/constexpr-new3.C   | 10 +--
>  gcc/testsuite/g++.dg/ext/constexpr-vla2.C |  4 +-
>  gcc/testsuite/g++.dg/ext/constexpr-vla3.C |  4 +-
>  gcc/testsuite/g++.dg/ubsan/pr63956.C  |  4 +-
>  .../25_algorithms/equal/constexpr_neg.cc  |  7 +-
>  25 files changed, 111 insertions(+), 101 deletions(-)
> 
> diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> index bdbc12144a7..74045477a92 100644
> --- a/gcc/cp/constexpr.cc
> +++ b/gcc/cp/constexpr.cc
> @@ -1165,10 +1165,12 @@ public:
>hash_set *modifiable;
>/* Number of heap VAR_DECL deallocations.  */
>unsigned h

Re: [PATCH v2 1/3] c++: Track lifetimes in constant evaluation [PR70331, PR96630, PR98675]

2023-06-26 Thread Patrick Palka via Gcc-patches
On Sun, 25 Jun 2023, Nathaniel Shead wrote:

> On Fri, Jun 23, 2023 at 12:43:21PM -0400, Patrick Palka wrote:
> > On Wed, 29 Mar 2023, Nathaniel Shead via Gcc-patches wrote:
> > 
> > > This adds rudimentary lifetime tracking in C++ constexpr contexts,
> > > allowing the compiler to report errors with using values after their
> > > backing has gone out of scope. We don't yet handle other ways of ending
> > > lifetimes (e.g. explicit destructor calls).
> > 
> > Awesome!
> > 
> > > 
> > >   PR c++/96630
> > >   PR c++/98675
> > >   PR c++/70331
> > > 
> > > gcc/cp/ChangeLog:
> > > 
> > >   * constexpr.cc (constexpr_global_ctx::put_value): Mark value as
> > >   in lifetime.
> > >   (constexpr_global_ctx::remove_value): Mark value as expired.
> > >   (cxx_eval_call_expression): Remove comment that is no longer
> > >   applicable.
> > >   (non_const_var_error): Add check for expired values.
> > >   (cxx_eval_constant_expression): Add checks for expired values. Forget
> > >   local variables at end of bind expressions. Forget temporaries at end
> > >   of cleanup points.
> > >   * cp-tree.h (struct lang_decl_base): New flag to track expired values
> > >   in constant evaluation.
> > >   (DECL_EXPIRED_P): Access the new flag.
> > >   (SET_DECL_EXPIRED_P): Modify the new flag.
> > >   * module.cc (trees_out::lang_decl_bools): Write out the new flag.
> > >   (trees_in::lang_decl_bools): Read in the new flag.
> > > 
> > > gcc/testsuite/ChangeLog:
> > > 
> > >   * g++.dg/cpp0x/constexpr-ice20.C: Update error raised by test.
> > >   * g++.dg/cpp1y/constexpr-lifetime1.C: New test.
> > >   * g++.dg/cpp1y/constexpr-lifetime2.C: New test.
> > >   * g++.dg/cpp1y/constexpr-lifetime3.C: New test.
> > >   * g++.dg/cpp1y/constexpr-lifetime4.C: New test.
> > >   * g++.dg/cpp1y/constexpr-lifetime5.C: New test.
> > > 
> > > Signed-off-by: Nathaniel Shead 
> > > ---
> > >  gcc/cp/constexpr.cc   | 69 +++
> > >  gcc/cp/cp-tree.h  | 10 ++-
> > >  gcc/cp/module.cc  |  2 +
> > >  gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C  |  2 +-
> > >  .../g++.dg/cpp1y/constexpr-lifetime1.C| 13 
> > >  .../g++.dg/cpp1y/constexpr-lifetime2.C| 20 ++
> > >  .../g++.dg/cpp1y/constexpr-lifetime3.C| 13 
> > >  .../g++.dg/cpp1y/constexpr-lifetime4.C| 11 +++
> > >  .../g++.dg/cpp1y/constexpr-lifetime5.C| 11 +++
> > >  9 files changed, 137 insertions(+), 14 deletions(-)
> > >  create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime1.C
> > >  create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime2.C
> > >  create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime3.C
> > >  create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime4.C
> > >  create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C
> > > 
> > > diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> > > index 3de60cfd0f8..bdbc12144a7 100644
> > > --- a/gcc/cp/constexpr.cc
> > > +++ b/gcc/cp/constexpr.cc
> > > @@ -1185,10 +1185,22 @@ public:
> > >void put_value (tree t, tree v)
> > >{
> > >  bool already_in_map = values.put (t, v);
> > > +if (!already_in_map && DECL_P (t))
> > > +  {
> > > + if (!DECL_LANG_SPECIFIC (t))
> > > +   retrofit_lang_decl (t);
> > > + if (DECL_LANG_SPECIFIC (t))
> > > +   SET_DECL_EXPIRED_P (t, false);
> > > +  }
> > 
> > Since this new flag would only be used only during constexpr evaluation,
> > could we instead use an on-the-side hash_set in constexpr_global_ctx for
> > tracking expired-ness?  That way we won't have to allocate a
> > DECL_LANG_SPECIFIC structure for decls that lack it, and won't have to
> > worry about the flag in other parts of the compiler.
> 
> I've tried this but I haven't been able to get it to work well. The main
> issue I'm running into is the caching of function calls in constant
> evaluation. For example, consider the following:
> 
> constexpr const double& test() {
>   const double& local = 3.0;
>   return local;
> }
> 
> constexpr int foo(const double&) { return 5; }
> 
> constexpr int a = foo(test());
> static_assert(test() == 3.0);
> 
> When constant-evaluating 'a', we evaluate 'test()'. It returns a value
> that ends its lifetime immediately, so we mark this in 'ctx->global' as
> expired. However, 'foo()' never actually evaluates this expired value,
> so the initialisation of 'a' succeeds.
> 
> However, then when the static assertion attempts to constant evaluate a
> second time, the result of 'test' has already been cached, and we just
> get directly handed a value. This is a new constant evaluation, so
> 'ctx->global' has been reset, and because we just got the result of the
> cached function we don't actually know whether this is expired or not
> anymore, and so this compiles without any error in case it was valid.

Ouch, good catch..

> 
> I haven't yet been able to come up with a good way of

[PATCH] c++: cache partial template specialization selection

2023-06-28 Thread Patrick Palka via Gcc-patches
There's currently no cheap way to obtain the partial template
specialization (and arguments relative to it) that was selected for a
class or variable template specialization.  Our only option is to
compute the result from scratch via most_specialized_partial_spec.

For class templates this isn't really an issue because we usually need
this information just once, upon instantiation.  But for variable
templates we need it upon specialization and later upon instantiation.
It'd be good for this information to be readily available in general
however.

To that end, this patch adds a TI_PARTIAL_INFO field to TEMPLATE_INFO
that holds another TEMPLATE_INFO consisting of the partial template and
arguments relative to it, which most_specialized_partial_spec then
uses to transparently cache its (now TEMPLATE_INFO) result.

Similarly, there's no easy way to go from the DECL_TEMPLATE_RESULT of a
partial TEMPLATE_DECL back to the TEMPLATE_DECL.  (Our best option is to
walk the DECL_TEMPLATE_SPECIALIZATIONS list of the primary TEMPLATE_DECL.)
So this patch also uses this new field to link these entities in this
other direction.

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?  Memory usage increases by ~0.2% overall with this patch (due to
the larger TEMPLATE_INFO, which now is the same size as TREE_LIST),
which seems acceptable.

gcc/cp/ChangeLog:

* cp-tree.h (tree_template_info::partial): New data member.
(TI_PARTIAL_INFO): New tree accessor.
(most_specialized_partial_spec): Add defaulted bool parameter.
* module.cc (trees_out::core_vals) :
Stream TI_PARTIAL_INFO.
(trees_in::core_vals) : Likewise.
* parser.cc (specialization_of): Adjust after making
most_specialized_partial_spec return TEMPLATE_INFO instead
of TREE_LIST.
* pt.cc (process_partial_specialization): Set TI_PARTIAL_INFO
of 'decl' to point back to the partial TEMPLATE_DECL.  Likewise
(and pass rechecking=true to most_specialization_partial_spec).
(instantiate_class_template): Likewise.
(instantiate_template): Set TI_PARTIAL_INFO to the result of
most_specialization_partial_spec after forming a variable
template specialization.
(most_specialized_partial_spec): Add 'rechecking' parameter.
Exit early if the template is not primary.  Use the TI_PARTIAL_INFO
of the corresponding TEMPLATE_INFO as a cache unless 'rechecking'
is true.  Don't bother setting TREE_TYPE of each TREE_LIST.
(instantiate_decl): Adjust after making
most_specialized_partial_spec return TEMPLATE_INFO instead of
TREE_LIST.
* ptree.cc (cxx_print_xnode) : Dump
TI_PARTIAL_INFO.
---
 gcc/cp/cp-tree.h | 11 ++-
 gcc/cp/module.cc |  2 ++
 gcc/cp/parser.cc |  6 ++--
 gcc/cp/pt.cc | 75 +++-
 gcc/cp/ptree.cc  |  3 ++
 5 files changed, 66 insertions(+), 31 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 83982233111..fe94af46346 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1564,6 +1564,7 @@ struct GTY(()) tree_template_info {
   struct tree_base base;
   tree tmpl;
   tree args;
+  tree partial;
   vec *deferred_access_checks;
 };
 
@@ -3755,6 +3756,14 @@ struct GTY(()) lang_decl {
   ((struct tree_template_info*)TEMPLATE_INFO_CHECK (NODE))->args
 #define TI_PENDING_TEMPLATE_FLAG(NODE) \
   TREE_LANG_FLAG_1 (TEMPLATE_INFO_CHECK (NODE))
+
+/* For a class or variable template specialization, this contains the
+   TEMPLATE_INFO result of most_specialized_partial_spec, i.e. the selected
+   partial template specialization and arguments relative to it.  */
+#define TI_PARTIAL_INFO(NODE) \
+  (gcc_checking_assert (PRIMARY_TEMPLATE_P (TI_TEMPLATE (NODE))), \
+   ((struct tree_template_info*)NODE)->partial)
+
 /* For a given TREE_VEC containing a template argument list,
this property contains the number of arguments that are not
defaulted.  */
@@ -7397,7 +7406,7 @@ extern bool comp_template_args(tree, 
tree, tree * = NULL,
 extern int template_args_equal  (tree, tree, bool = false);
 extern tree maybe_process_partial_specialization (tree);
 extern tree most_specialized_instantiation (tree);
-extern tree most_specialized_partial_spec   (tree, tsubst_flags_t);
+extern tree most_specialized_partial_spec   (tree, tsubst_flags_t, bool = 
false);
 extern void print_candidates   (tree);
 extern void instantiate_pending_templates  (int);
 extern tree tsubst_default_argument(tree, int, tree, tree,
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index ecde98d69b4..ea362bdffa4 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -6364,6 +6364,7 @@ trees_out::core_vals (tree t)
   {
WT (((lang_tree_node *)t)->template_info.tmpl);
WT (((lang_tree_node *)t)->template_info.args);
+   WT (((lang_tree_nod

Re: [PATCH] c++: Fix ICE with parameter pack of decltype(auto) [PR103497]

2023-06-28 Thread Patrick Palka via Gcc-patches
On Sat, Jun 24, 2023 at 9:24 AM Nathaniel Shead
 wrote:
>
> On Fri, Jun 23, 2023 at 11:59:51AM -0400, Patrick Palka wrote:
> > Hi,
> >
> > On Sat, 22 Apr 2023, Nathaniel Shead via Gcc-patches wrote:
> >
> > > Bootstrapped and tested on x86_64-pc-linux-gnu.
> > >
> > > -- 8< --
> > >
> > > This patch raises an error early when the decltype(auto) specifier is
> > > used as a parameter of a function. This prevents any issues with an
> > > unexpected tree type later on when performing the call.
> >
> > Thanks very much for the patch!  Some minor comments below.
> >
> > >
> > > PR 103497
> >
> > We should include the bug component name when referring to the PR in the
> > commit message (i.e. PR c++/103497) so that upon pushing the patch the
> > post-commit hook automatically adds a comment to the PR reffering to the
> > commit.  I could be wrong but AFAIK the hook only performs this when the
> > component name is included.
>
> Thanks for the review! Fixed.
>
> > >
> > > gcc/cp/ChangeLog:
> > >
> > > * parser.cc (cp_parser_simple_type_specifier): Add check for
> > > decltype(auto) as function parameter.
> > >
> > > gcc/testsuite/ChangeLog:
> > >
> > > * g++.dg/pr103497.C: New test.
> > >
> > > Signed-off-by: Nathaniel Shead 
> > > ---
> > >  gcc/cp/parser.cc| 10 ++
> > >  gcc/testsuite/g++.dg/pr103497.C |  7 +++
> > >  2 files changed, 17 insertions(+)
> > >  create mode 100644 gcc/testsuite/g++.dg/pr103497.C
> > >
> > > diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> > > index e5f032f2330..1415e07e152 100644
> > > --- a/gcc/cp/parser.cc
> > > +++ b/gcc/cp/parser.cc
> > > @@ -19884,6 +19884,16 @@ cp_parser_simple_type_specifier (cp_parser* 
> > > parser,
> > >&& cp_lexer_peek_nth_token (parser->lexer, 2)->type != CPP_SCOPE)
> > >  {
> > >type = saved_checks_value (token->u.tree_check_value);
> > > +  /* Within a function parameter declaration, decltype(auto) is 
> > > always an
> > > +error.  */
> > > +  if (parser->auto_is_implicit_function_template_parm_p
> > > + && TREE_CODE (type) == TEMPLATE_TYPE_PARM
> >
> > We could check is_auto (type) here instead, to avoid any confusion with
> > checking AUTO_IS_DECLTYPE for a non-auto TEMPLATE_TYPE_PARM.
> >
> > > + && AUTO_IS_DECLTYPE (type))
> > > +   {
> > > + error_at (token->location,
> > > +   "cannot declare a parameter with %");
> > > + type = error_mark_node;
> > > +   }
> > >if (decl_specs)
> > > {
> > >   cp_parser_set_decl_spec_type (decl_specs, type,
> > > diff --git a/gcc/testsuite/g++.dg/pr103497.C 
> > > b/gcc/testsuite/g++.dg/pr103497.C
> > > new file mode 100644
> > > index 000..bcd421c2907
> > > --- /dev/null
> > > +++ b/gcc/testsuite/g++.dg/pr103497.C
> > > @@ -0,0 +1,7 @@
> > > +// { dg-do compile { target c++14 } }
> > > +
> > > +void foo(decltype(auto)... args);  // { dg-error "parameter with 
> > > .decltype.auto..|no parameter packs" }
> >
> > I noticed for
> >
> >   void foo(decltype(auto) arg);
> >
> > we already issue an identical error from grokdeclarator.  Perhaps we could
> > instead extend the error handling there to detect decltype(auto)... as well,
> > rather than adding new error handling in cp_parser_simple_type_specifier?
>
> Ah thanks, I didn't notice this; this simplifies the change a fair bit.
> How about this patch instead?

LGTM! Though I can't approve the patch myself.

>
> Regtested on x86_64-pc-linux-gnu.
>
> -- 8< --
>
> This patch ensures that checks for usages of 'auto' in function
> parameters also consider parameter packs, since 'type_uses_auto' does
> not seem to consider this case.
>
> PR c++/103497
>
> gcc/cp/ChangeLog:
>
> * decl.cc (grokdeclarator): Check for decltype(auto) in
> parameter pack.
>
> gcc/testsuite/ChangeLog:
>
> * g++.dg/cpp1y/decltype-auto-103497.C: New test.
>
> Signed-off-by: Nathaniel Shead 
> ---
>  gcc/cp/decl.cc| 3 +++
>  gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C | 8 
>  2 files changed, 11 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C
>
> diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> index 60f107d50c4..aaf691fce68 100644
> --- a/gcc/cp/decl.cc
> +++ b/gcc/cp/decl.cc
> @@ -14044,6 +14044,9 @@ grokdeclarator (const cp_declarator *declarator,
> error ("cannot use %<::%> in parameter declaration");
>
>tree auto_node = type_uses_auto (type);
> +  if (!auto_node && parameter_pack_p)
> +   auto_node = type_uses_auto (PACK_EXPANSION_PATTERN (type));
> +
>if (auto_node && !(cxx_dialect >= cxx17 && template_parm_flag))
> {
>   if (cxx_dialect >= cxx14)
> diff --git a/gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C 
> b/gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C
> new file mode 100644
> index 000..cedd661710c
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C
> @@ 

Re: [PATCH] c++: redundant targ coercion for var/alias tmpls

2023-06-28 Thread Patrick Palka via Gcc-patches
On Wed, Jun 28, 2023 at 11:50 AM Jason Merrill  wrote:
>
> On 6/23/23 12:23, Patrick Palka wrote:
> > On Fri, 23 Jun 2023, Jason Merrill wrote:
> >
> >> On 6/21/23 13:19, Patrick Palka wrote:
> >>> When stepping through the variable/alias template specialization code
> >>> paths, I noticed we perform template argument coercion twice: first from
> >>> instantiate_alias_template / finish_template_variable and again from
> >>> tsubst_decl (during instantiate_template).  It should suffice to perform
> >>> coercion once.
> >>>
> >>> To that end patch elides this second coercion from tsubst_decl when
> >>> possible.  We can't get rid of it completely because we don't always
> >>> specialize a variable template from finish_template_variable: we could
> >>> also be doing so directly from instantiate_template during variable
> >>> template partial specialization selection, in which case the coercion
> >>> from tsubst_decl would be the first and only coercion.
> >>
> >> Perhaps we should be coercing in lookup_template_variable rather than
> >> finish_template_variable?
> >
> > Ah yes, there's a patch for that at
> > https://gcc.gnu.org/pipermail/gcc-patches/2023-May/617377.html :)
>
> So after that patch, can we get rid of the second coercion completely?

On second thought it should be possible to get rid of it, if we
rearrange things to always pass the primary arguments to tsubst_decl,
and perform partial specialization selection from there instead of
instantiate_template.  Let me try...

>
> Jason
>



[PATCH] c++: NSDMI instantiation during overload resolution [PR110468]

2023-06-29 Thread Patrick Palka via Gcc-patches
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk/13/12?

-- >8 --

Here we find ourselves instantiating the NSDMI for A<1>::m when
computing argument conversions during overload resolution, and
thus tf_conv is set.  This causes mark_used for the constructor
used in the NSDMI to exit early and not instantiate its noexcept-spec,
leading to an ICE from nothrow_spec_p.

This patch fixes this by clearing any unusual tsubst flags during
instantiation of an NSDMI, since the result should be independent of
the context that requires the instantiation.

PR c++/110468

gcc/cp/ChangeLog:

* init.cc (maybe_instantiate_nsdmi_init): Mask out all
tsubst flags except for tf_warning_or_error.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/noexcept79.C: New test.
---
 gcc/cp/init.cc  |  4 
 gcc/testsuite/g++.dg/cpp0x/noexcept79.C | 18 ++
 2 files changed, 22 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/noexcept79.C

diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index af6e30f511e..f01a11c5299 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -579,6 +579,10 @@ maybe_instantiate_nsdmi_init (tree member, tsubst_flags_t 
complain)
   /* tsubst_decl uses void_node to indicate an uninstantiated DMI.  */
   if (init == void_node)
 {
+  /* The result of NSDMI instantiation should be independent of
+the tsubst flags we're given.  */
+  complain &= tf_warning_or_error;
+
   init = DECL_INITIAL (DECL_TI_TEMPLATE (member));
   location_t expr_loc
= cp_expr_loc_or_loc (init, DECL_SOURCE_LOCATION (member));
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept79.C 
b/gcc/testsuite/g++.dg/cpp0x/noexcept79.C
new file mode 100644
index 000..d1f54d14431
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/noexcept79.C
@@ -0,0 +1,18 @@
+// PR c++/110468
+// { dg-do compile { target c++11 } }
+
+template
+struct variant {
+  variant() noexcept(T > 0);
+};
+
+template
+struct A {
+  variant m = {};
+};
+
+struct B {
+  B(A<1>);
+};
+
+B b = {{}};
-- 
2.41.0.199.ga9e066fa63



[PATCH] c++: unpropagated CONSTRUCTOR_MUTABLE_POISON [PR110463]

2023-06-29 Thread Patrick Palka via Gcc-patches
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk/13?

-- >8 --

cp_fold is neglecting to propagate CONSTRUCTOR_MUTABLE_POISON when folding
a CONSTRUCTOR initializer, which for the below testcase causes us to fail
to reject a mutable member access of a constexpr variable during constexpr
evaluation.

PR c++/110463

gcc/cp/ChangeLog:

* cp-gimplify.cc (cp_fold) : Propagate
CONSTRUCTOR_MUTABLE_POISON.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/constexpr-mutable6.C: New test.
---
 gcc/cp/cp-gimplify.cc  |  2 ++
 .../g++.dg/cpp0x/constexpr-mutable6.C  | 18 ++
 2 files changed, 20 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-mutable6.C

diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
index 853b1e44236..f5734197774 100644
--- a/gcc/cp/cp-gimplify.cc
+++ b/gcc/cp/cp-gimplify.cc
@@ -3079,6 +3079,8 @@ cp_fold (tree x, fold_flags_t flags)
x = build_constructor (TREE_TYPE (x), nelts);
CONSTRUCTOR_PLACEHOLDER_BOUNDARY (x)
  = CONSTRUCTOR_PLACEHOLDER_BOUNDARY (org_x);
+   CONSTRUCTOR_MUTABLE_POISON (x)
+ = CONSTRUCTOR_MUTABLE_POISON (org_x);
  }
if (VECTOR_TYPE_P (TREE_TYPE (x)))
  x = fold (x);
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-mutable6.C 
b/gcc/testsuite/g++.dg/cpp0x/constexpr-mutable6.C
new file mode 100644
index 000..2c946e388ab
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-mutable6.C
@@ -0,0 +1,18 @@
+// PR c++/110463
+// { dg-do compile { target c++11 } }
+
+struct U {
+  mutable int x = 1;
+};
+
+struct V {
+  mutable int y = 1+1;
+};
+
+int main() {
+  constexpr U u = {};
+  constexpr int x = u.x; // { dg-error "mutable" }
+
+  constexpr V v = {};
+  constexpr int y = v.y; // { dg-error "mutable" }
+}
-- 
2.41.0.199.ga9e066fa63



Re: [PATCH] libstdc++: Fix iostream init for Clang on darwin [PR110432]

2023-06-30 Thread Patrick Palka via Gcc-patches
On Fri, 30 Jun 2023, Jonathan Wakely wrote:

> Tested x86_64-linux. Patrick, PTAL.
> 
> -- >8 --
> 
> The __has_attribute(init_priority) check in  is true for Clang
> on darwin, which means that user code including  thinks the
> library will initialize the global streams. However, when libstdc++ is
> built by GCC on darwin, the __has_attribute(init_priority) check is
> false, which means that the library thinks that user code will do the
> initialization when  is included. This means that the
> initialization is never done.
> 
> Add an autoconf check so that the header and the library both make their
> decision based on the static properties of GCC at build time, with a
> consistent outcome.
> 
> As a belt and braces check, also do the initialization in  if
> the compiler including that header doesn't support the attribute (even
> if the library also containers the initialization). This might result in
> redundant initialization done in , but ensures the
> initialization happens somewhere if there's any doubt about the
> attribute working correctly due to missing linker support.
> 
> libstdc++-v3/ChangeLog:
> 
>   PR libstdc++/110432
>   * acinclude.m4 (GLIBCXX_CHECK_INIT_PRIORITY): New.
>   * config.h.in: Regenerate.
>   * configure: Regenerate.
>   * configure.ac: Use GLIBCXX_CHECK_INIT_PRIORITY.
>   * include/std/iostream:

Missing ChangeLog entry?

>   * src/c++98/ios_base_init.h: Use new autoconf macro instead of
>   __has_attribute.
> ---
>  libstdc++-v3/acinclude.m4  | 27 ++
>  libstdc++-v3/config.h.in   |  3 ++
>  libstdc++-v3/configure | 51 ++
>  libstdc++-v3/configure.ac  |  3 ++
>  libstdc++-v3/include/std/iostream  |  2 +-
>  libstdc++-v3/src/c++98/ios_base_init.h |  2 +-
>  6 files changed, 86 insertions(+), 2 deletions(-)
> 
> diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4
> index 277ae10e031..823832f97d4 100644
> --- a/libstdc++-v3/acinclude.m4
> +++ b/libstdc++-v3/acinclude.m4
> @@ -5680,6 +5680,33 @@ AC_DEFUN([GLIBCXX_CHECK_ALIGNAS_CACHELINE], [
>AC_LANG_RESTORE
>  ])
>  
> +dnl
> +dnl Check whether iostream initialization should be done in the library,
> +dnl using the init_priority attribute.
> +dnl
> +dnl Defines:
> +dnl  _GLIBCXX_USE_INIT_PRIORITY_ATTRIBUTE if GCC supports the init_priority
> +dnlattribute for the target.
> +dnl
> +AC_DEFUN([GLIBCXX_CHECK_INIT_PRIORITY], [
> +AC_LANG_SAVE
> +  AC_LANG_CPLUSPLUS
> +
> +  AC_MSG_CHECKING([whether init_priority attribute is supported])
> +  AC_TRY_COMPILE(, [
> +  #if ! __has_attribute(init_priority)
> +  #error init_priority not supported
> +  #endif
> +  ], [ac_init_priority=yes], [ac_init_priority=no])
> +  if test "$ac_init_priority" = yes; then
> +AC_DEFINE_UNQUOTED(_GLIBCXX_USE_INIT_PRIORITY_ATTRIBUTE, 1,
> +  [Define if init_priority should be used for iostream initialization.])
> +  fi
> +  AC_MSG_RESULT($ac_init_priority)
> +
> +  AC_LANG_RESTORE
> +])
> +
>  # Macros from the top-level gcc directory.
>  m4_include([../config/gc++filt.m4])
>  m4_include([../config/tls.m4])
> diff --git a/libstdc++-v3/configure.ac b/libstdc++-v3/configure.ac
> index 9770c178767..fc0f2522027 100644
> --- a/libstdc++-v3/configure.ac
> +++ b/libstdc++-v3/configure.ac
> @@ -550,6 +550,9 @@ GLIBCXX_ZONEINFO_DIR
>  # For src/c++11/shared_ptr.cc alignment.
>  GLIBCXX_CHECK_ALIGNAS_CACHELINE
>  
> +# For using init_priority in ios_init.cc
> +GLIBCXX_CHECK_INIT_PRIORITY
> +
>  # Define documentation rules conditionally.
>  
>  # See if makeinfo has been installed and is modern enough
> diff --git a/libstdc++-v3/include/std/iostream 
> b/libstdc++-v3/include/std/iostream
> index cfd124dcf43..ec337cf89dd 100644
> --- a/libstdc++-v3/include/std/iostream
> +++ b/libstdc++-v3/include/std/iostream
> @@ -75,7 +75,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>// For construction of filebuffers for cout, cin, cerr, clog et. al.
>// When the init_priority attribute is usable, we do this initialization
>// in the compiled library instead (src/c++98/globals_io.cc).
> -#if !__has_attribute(__init_priority__)
> +#if !(_GLIBCXX_USE_INIT_PRIORITY_ATTRIBUTE && __has_attribute(init_priority))

This should check __init_priority__ since init_priority is a non-reserved
name I think?  LGTM otherwise.

>static ios_base::Init __ioinit;
>  #elif defined(_GLIBCXX_SYMVER_GNU)
>__extension__ __asm (".globl _ZSt21ios_base_library_initv");
> diff --git a/libstdc++-v3/src/c++98/ios_base_init.h 
> b/libstdc++-v3/src/c++98/ios_base_init.h
> index b600ec3298e..f7edfc84625 100644
> --- a/libstdc++-v3/src/c++98/ios_base_init.h
> +++ b/libstdc++-v3/src/c++98/ios_base_init.h
> @@ -8,6 +8,6 @@
>  // constructor when statically linking with libstdc++.a), instead of
>  // doing so in (each TU that includes) .
>  // This needs to be done in the same TU that defines the stream objects.
> -#if __has_attribute(init_pri

[pushed] c++: redeclare_class_template and ttps [PR110523]

2023-07-10 Thread Patrick Palka via Gcc-patches
Tested on x86_64-pc-linux-gnu, pushed to trunk as obvious.

-- >8 --

Now that we cache level-lowered ttps we can end up processing the same
ttp multiple times via (multiple calls to) redeclare_class_template, so
we can't assume a ttp's DECL_CONTEXT is initially empty.

PR c++/110523

gcc/cp/ChangeLog:

* pt.cc (redeclare_class_template): Relax the ttp DECL_CONTEXT
assert, and downgrade it to a checking assert.

gcc/testsuite/ChangeLog:

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

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index d7d774fd9e5..076f788281e 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -6388,7 +6388,8 @@ redeclare_class_template (tree type, tree parms, tree 
cons)
 DECL_CONTEXT of the template for which they are a parameter.  */
   if (TREE_CODE (parm) == TEMPLATE_DECL)
{
- gcc_assert (DECL_CONTEXT (parm) == NULL_TREE);
+ gcc_checking_assert (DECL_CONTEXT (parm) == NULL_TREE
+  || DECL_CONTEXT (parm) == tmpl);
  DECL_CONTEXT (parm) = tmpl;
}
 }
diff --git a/gcc/testsuite/g++.dg/template/ttp37.C 
b/gcc/testsuite/g++.dg/template/ttp37.C
new file mode 100644
index 000..c5f4e99c20a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/ttp37.C
@@ -0,0 +1,15 @@
+// PR c++/110523
+
+template class>
+class basic_json;
+
+template
+struct json_pointer {
+  template class>
+  friend class basic_json;
+};
+
+template struct json_pointer;
+template struct json_pointer;
+template struct json_pointer;
+template struct json_pointer;
-- 
2.41.0.327.gaa9166bcc0



Re: [PATCH v3 0/3] c++: Track lifetimes in constant evaluation [PR70331,...]

2023-07-10 Thread Patrick Palka via Gcc-patches
On Sat, 1 Jul 2023, Nathaniel Shead wrote:

> This is an update of the patch series at
> https://gcc.gnu.org/pipermail/gcc-patches/2023-March/614811.html
> 
> Changes since v2:
> 
> - Use a separate 'hash_set' to track expired variables instead of
>   adding a flag to 'lang_decl_base'.
> - Use 'iloc_sentinel' to propagate location information down to
>   subexpressions instead of manually saving and falling back to a
>   parent expression's location.
> - Update more tests with improved error location information.

Thanks very much! This patch series looks good to me.

> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu.
> 
> ---
> 
> Nathaniel Shead (3):
>   c++: Track lifetimes in constant evaluation [PR70331,PR96630,PR98675]
>   c++: Improve constexpr error for dangling local variables
>   c++: Improve location information in constant evaluation
> 
>  gcc/cp/constexpr.cc   | 158 +++---
>  gcc/cp/semantics.cc   |   5 +-
>  gcc/cp/typeck.cc  |   5 +-
>  gcc/testsuite/g++.dg/cpp0x/constexpr-48089.C  |  10 +-
>  gcc/testsuite/g++.dg/cpp0x/constexpr-70323.C  |   8 +-
>  gcc/testsuite/g++.dg/cpp0x/constexpr-70323a.C |   8 +-
>  .../g++.dg/cpp0x/constexpr-delete2.C  |   5 +-
>  gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C  |   2 +-
>  gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C  |   1 +
>  .../g++.dg/cpp0x/constexpr-recursion.C|   6 +-
>  gcc/testsuite/g++.dg/cpp0x/overflow1.C|   2 +-
>  gcc/testsuite/g++.dg/cpp1y/constexpr-89285.C  |   5 +-
>  gcc/testsuite/g++.dg/cpp1y/constexpr-89481.C  |   3 +-
>  .../g++.dg/cpp1y/constexpr-lifetime1.C|  14 ++
>  .../g++.dg/cpp1y/constexpr-lifetime2.C|  20 +++
>  .../g++.dg/cpp1y/constexpr-lifetime3.C|  13 ++
>  .../g++.dg/cpp1y/constexpr-lifetime4.C|  11 ++
>  .../g++.dg/cpp1y/constexpr-lifetime5.C|  11 ++
>  .../g++.dg/cpp1y/constexpr-tracking-const14.C |   3 +-
>  .../g++.dg/cpp1y/constexpr-tracking-const16.C |   3 +-
>  .../g++.dg/cpp1y/constexpr-tracking-const18.C |   4 +-
>  .../g++.dg/cpp1y/constexpr-tracking-const19.C |   4 +-
>  .../g++.dg/cpp1y/constexpr-tracking-const21.C |   4 +-
>  .../g++.dg/cpp1y/constexpr-tracking-const22.C |   4 +-
>  .../g++.dg/cpp1y/constexpr-tracking-const3.C  |   3 +-
>  .../g++.dg/cpp1y/constexpr-tracking-const4.C  |   3 +-
>  .../g++.dg/cpp1y/constexpr-tracking-const7.C  |   3 +-
>  gcc/testsuite/g++.dg/cpp1y/constexpr-union5.C |   4 +-
>  gcc/testsuite/g++.dg/cpp1y/pr68180.C  |   4 +-
>  .../g++.dg/cpp1z/constexpr-lambda6.C  |   4 +-
>  .../g++.dg/cpp1z/constexpr-lambda8.C  |   5 +-
>  gcc/testsuite/g++.dg/cpp2a/bit-cast11.C   |  10 +-
>  gcc/testsuite/g++.dg/cpp2a/bit-cast12.C   |  10 +-
>  gcc/testsuite/g++.dg/cpp2a/bit-cast14.C   |  14 +-
>  gcc/testsuite/g++.dg/cpp2a/constexpr-98122.C  |   4 +-
>  .../g++.dg/cpp2a/constexpr-dynamic17.C|   5 +-
>  gcc/testsuite/g++.dg/cpp2a/constexpr-init1.C  |   5 +-
>  gcc/testsuite/g++.dg/cpp2a/constexpr-new12.C  |   6 +-
>  gcc/testsuite/g++.dg/cpp2a/constexpr-new3.C   |  10 +-
>  gcc/testsuite/g++.dg/cpp2a/constinit10.C  |   5 +-
>  .../g++.dg/cpp2a/is-corresponding-member4.C   |   4 +-
>  gcc/testsuite/g++.dg/ext/constexpr-vla2.C |   4 +-
>  gcc/testsuite/g++.dg/ext/constexpr-vla3.C |   4 +-
>  gcc/testsuite/g++.dg/ubsan/pr63956.C  |  23 +--
>  .../g++.dg/warn/Wreturn-local-addr-6.C|   3 -
>  .../25_algorithms/equal/constexpr_neg.cc  |   7 +-
>  .../testsuite/26_numerics/gcd/105844.cc   |  10 +-
>  .../testsuite/26_numerics/lcm/105844.cc   |  14 +-
>  48 files changed, 330 insertions(+), 143 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime1.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime2.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime3.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime4.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C
> 
> -- 
> 2.41.0
> 
> 



[PATCH] c++: coercing variable template from current inst [PR110580]

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

-- >8 --

Here during ahead of time coercion of the variable template-id v1,
since we pass only the innermost arguments to coerce_template_parms (and
outer arguments are still dependent at this point), substitution of the
default template argument V=U prematurely lowers U from level 2 to level 1.
Thus we incorrectly resolve v1 to v1 (effectively) instead
of to v1.

Coercion of a class/alias template-id on the other hand is always done
using the full set of arguments relative to the most general template,
so ahead of time coercion there does the right thing.  I suppose we
should do the same for variable template-ids.

PR c++/110580

gcc/cp/ChangeLog:

* pt.cc (lookup_template_variable): Pass all arguments to
coerce_template_parms, and use the innermost parameters from
the most general template.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1y/var-templ83.C: New test.
---
 gcc/cp/pt.cc |  4 +++-
 gcc/testsuite/g++.dg/cpp1y/var-templ83.C | 16 
 2 files changed, 19 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/var-templ83.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 076f788281e..fa15b75b9c5 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -10345,7 +10345,9 @@ lookup_template_variable (tree templ, tree arglist, 
tsubst_flags_t complain)
   if (flag_concepts && variable_concept_p (templ))
 return build_concept_check (templ, arglist, tf_none);
 
-  tree parms = DECL_INNERMOST_TEMPLATE_PARMS (templ);
+  tree gen_templ = most_general_template (templ);
+  tree parms = DECL_INNERMOST_TEMPLATE_PARMS (gen_templ);
+  arglist = add_outermost_template_args (templ, arglist);
   arglist = coerce_template_parms (parms, arglist, templ, complain);
   if (arglist == error_mark_node)
 return error_mark_node;
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ83.C 
b/gcc/testsuite/g++.dg/cpp1y/var-templ83.C
new file mode 100644
index 000..f5268f258d7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/var-templ83.C
@@ -0,0 +1,16 @@
+// PR c++/110580
+// { dg-do compile { target c++14 } }
+
+template
+struct A {
+  template
+  static constexpr bool v1 = __is_same(U, V);
+
+  template
+  static constexpr bool v2 = !__is_same(U, V);
+
+  static_assert(v1, "");
+  static_assert(v2, "");
+};
+
+template struct A;
-- 
2.41.0.327.gaa9166bcc0



[PATCH 1/2] c++: factor out TYPENAME_TYPE substitution

2023-02-13 Thread Patrick Palka via Gcc-patches
[N.B. this is a corrected version of
https://gcc.gnu.org/pipermail/gcc-patches/2022-November/607443.html ]

This patch factors out the TYPENAME_TYPE case of tsubst into a separate
function tsubst_typename_type.  It also factors out the two tsubst flags
controlling TYPENAME_TYPE substitution, tf_keep_type_decl and tf_tst_ok,
into distinct boolean parameters of this new function (and of
make_typename_type).  Consequently, callers which used to pass tf_tst_ok
to tsubst now instead must directly call tsubst_typename_type when
appropriate.  In a subsequent patch we'll add another flag to
tsubst_typename_type controlling whether we want to ignore non-types
during the qualified lookup.

gcc/cp/ChangeLog:

* cp-tree.h (enum tsubst_flags): Remove tf_keep_type_decl
and tf_tst_ok.
(make_typename_type): Add two trailing boolean parameters
defaulted to false.
* decl.cc (make_typename_type): Replace uses of
tf_keep_type_decl and tf_tst_ok with the corresponding new
boolean parameters.
* pt.cc (tsubst_typename_type): New, factored out from tsubst
and adjusted after removing tf_keep_type_decl and tf_tst_ok.
(tsubst_decl) : Conditionally call
tsubst_typename_type directly instead of using tf_tst_ok.
(tsubst) : Call tsubst_typename_type.
(tsubst_copy) : Conditionally call
tsubst_typename_type directly instead of using tf_tst_ok.
(tsubst_copy_and_build) : Likewise.
: Likewise.
---
 gcc/cp/cp-tree.h |   9 +-
 gcc/cp/decl.cc   |  17 ++--
 gcc/cp/pt.cc | 223 +--
 3 files changed, 134 insertions(+), 115 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 06bc64a6b8d..a7c5765fc33 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5573,8 +5573,7 @@ enum tsubst_flags {
   tf_error = 1 << 0,/* give error messages  */
   tf_warning = 1 << 1,  /* give warnings too  */
   tf_ignore_bad_quals = 1 << 2, /* ignore bad cvr qualifiers */
-  tf_keep_type_decl = 1 << 3,   /* retain typedef type decls
-   (make_typename_type use) */
+  /* 1 << 3 available */
   tf_ptrmem_ok = 1 << 4,/* pointers to member ok (internal
instantiate_type use) */
   tf_user = 1 << 5, /* found template must be a user template
@@ -5594,8 +5593,7 @@ 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 (C++17 or later).  */
+  /* 1 << 12 available */
   tf_dguide = 1 << 13, /* Building a deduction guide from a ctor.  */
   /* Convenient substitution flags combinations.  */
   tf_warning_or_error = tf_warning | tf_error
@@ -6846,7 +6844,8 @@ extern tree declare_local_label   (tree);
 extern tree define_label   (location_t, tree);
 extern void check_goto (tree);
 extern bool check_omp_return   (void);
-extern tree make_typename_type (tree, tree, enum tag_types, 
tsubst_flags_t);
+extern tree make_typename_type (tree, tree, enum tag_types, 
tsubst_flags_t,
+bool = false, bool = false);
 extern tree build_typename_type(tree, tree, tree, 
tag_types);
 extern tree make_unbound_class_template(tree, tree, tree, 
tsubst_flags_t);
 extern tree make_unbound_class_template_raw(tree, tree, tree);
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index d606b31d7a7..430533606b0 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -4228,14 +4228,17 @@ build_typename_type (tree context, tree name, tree 
fullname,
 /* Resolve `typename CONTEXT::NAME'.  TAG_TYPE indicates the tag
provided to name the type.  Returns an appropriate type, unless an
error occurs, in which case error_mark_node is returned.  If we
-   locate a non-artificial TYPE_DECL and TF_KEEP_TYPE_DECL is set, we
+   locate a non-artificial TYPE_DECL and KEEP_TYPE_DECL is true, we
return that, rather than the _TYPE it corresponds to, in other
-   cases we look through the type decl.  If TF_ERROR is set, complain
-   about errors, otherwise be quiet.  */
+   cases we look through the type decl.  If TEMPLATE_OK is true and
+   we found a TEMPLATE_DECL then we return a CTAD placeholder for the
+   TEMPLATE_DECL.  If TF_ERROR is set, complain about errors, otherwise
+   be quiet.  */
 
 tree
 make_typename_type (tree context, tree name, enum tag_types tag_type,
-   tsubst_flags_t complain)
+   tsubst_flags_t complain, bool keep_type_decl /* = false */,
+   bool template_ok /* 

[PATCH 2/2] c++: TYPENAME_TYPE lookup ignoring non-types [PR107773]

2023-02-13 Thread Patrick Palka via Gcc-patches
[N.B. this is a corrected version of
https://gcc.gnu.org/pipermail/gcc-patches/2022-November/607443.html ]

Currently when resolving a TYPENAME_TYPE for 'typename T::m' via
make_typename_type, we consider only type bindings of 'm' and ignore
non-type ones.  But [temp.res.general]/3 says, in a note, "the usual
qualified name lookup ([basic.lookup.qual]) applies even in the presence
of 'typename'", and qualified name lookup doesn't discriminate between
type and non-type bindings.  So when resolving such a TYPENAME_TYPE
we want the lookup to consider all bindings.

An exception is when we have a TYPENAME_TYPE corresponding to the
qualifying scope appearing before the :: scope resolution operator, such
as 'T::type' in 'typename T::type::m'.  In that case, [basic.lookup.qual]/1
applies, and lookup for such a TYPENAME_TYPE must ignore non-type
bindings.  So in order to correctly handle all cases, make_typename_type
needs an additional flag controlling whether lookup should ignore
non-types or not.

To that end this patch adds a type_only flag to make_typename_type and
defaults it to false (do not ignore non-types).  In contexts where we do
want to ignore non-types (when substituting into the scope of a
TYPENAME_TYPE, SCOPE_REF, USING_DECL) we call tsubst_typename_type
directly with type_only=true.

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

PR c++/107773

gcc/cp/ChangeLog:

* cp-tree.h (make_typename_type): Add another boolean parameter
that defaults to false.
* decl.cc (make_typename_type): Use lookup_member instead of
lookup_field.  Pass want_type=type_only instead of =false to
lookup_member.  Generalize format specifier in diagnostic to
handle both type and non-type bindings.
* pt.cc (tsubst_typename_type): Add another boolean parameter
that defaults to false and pass it to make_typename_type.  If
TYPE_CONTEXT is a TYPENAME_TYPE recurse with type_only=true
instead of substituting it via tsubst.
(tsubst_decl) : If the scpoe is a TYPENAME_TYPE
call tsubst_typename_type directly with type_only=true instead
of substituting it via tsubst.
(tsubst_qualified_id): Likewise.
* search.cc (lookup_member): Document default argument.

gcc/testsuite/ChangeLog:

* g++.dg/template/typename24.C: New test.
* g++.dg/template/typename25.C: New test.
* g++.dg/template/typename26.C: New test.
---
 gcc/cp/cp-tree.h   |  2 +-
 gcc/cp/decl.cc | 14 -
 gcc/cp/pt.cc   | 24 +++
 gcc/cp/search.cc   |  2 +-
 gcc/testsuite/g++.dg/template/typename24.C | 18 
 gcc/testsuite/g++.dg/template/typename25.C | 34 ++
 gcc/testsuite/g++.dg/template/typename26.C | 20 +
 7 files changed, 100 insertions(+), 14 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/typename24.C
 create mode 100644 gcc/testsuite/g++.dg/template/typename25.C
 create mode 100644 gcc/testsuite/g++.dg/template/typename26.C

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index a7c5765fc33..1241dbf8037 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6845,7 +6845,7 @@ extern tree define_label  (location_t, 
tree);
 extern void check_goto (tree);
 extern bool check_omp_return   (void);
 extern tree make_typename_type (tree, tree, enum tag_types, 
tsubst_flags_t,
-bool = false, bool = false);
+bool = false, bool = false, 
bool = false);
 extern tree build_typename_type(tree, tree, tree, 
tag_types);
 extern tree make_unbound_class_template(tree, tree, tree, 
tsubst_flags_t);
 extern tree make_unbound_class_template_raw(tree, tree, tree);
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 430533606b0..c741dc23d99 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -4232,13 +4232,14 @@ build_typename_type (tree context, tree name, tree 
fullname,
return that, rather than the _TYPE it corresponds to, in other
cases we look through the type decl.  If TEMPLATE_OK is true and
we found a TEMPLATE_DECL then we return a CTAD placeholder for the
-   TEMPLATE_DECL.  If TF_ERROR is set, complain about errors, otherwise
-   be quiet.  */
+   TEMPLATE_DECL.  If TYPE_ONLY is true, lookup of NAME in CONTEXT
+   ignores non-type bindings.  If TF_ERROR is set, complain about errors,
+   otherwise be quiet.  */
 
 tree
 make_typename_type (tree context, tree name, enum tag_types tag_type,
tsubst_flags_t complain, bool keep_type_decl /* = false */,
-   bool template_ok /* = false */)
+   bool template_ok /* = false */, bool type_only /* = false 
*/)
 {
   tree

Re: [PATCH 1/2] c++: factor out TYPENAME_TYPE substitution

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

> On 2/13/23 09:23, Patrick Palka wrote:
> > [N.B. this is a corrected version of
> > https://gcc.gnu.org/pipermail/gcc-patches/2022-November/607443.html ]
> > 
> > This patch factors out the TYPENAME_TYPE case of tsubst into a separate
> > function tsubst_typename_type.  It also factors out the two tsubst flags
> > controlling TYPENAME_TYPE substitution, tf_keep_type_decl and tf_tst_ok,
> > into distinct boolean parameters of this new function (and of
> > make_typename_type).  Consequently, callers which used to pass tf_tst_ok
> > to tsubst now instead must directly call tsubst_typename_type when
> > appropriate.
> 
> Hmm, I don't love how that turns 4 lines into 8 more complex lines in each
> caller.  And the previous approach of saying "a CTAD placeholder is OK" seem
> like better abstraction than repeating the specific TYPENAME_TYPE handling in
> each place.

Ah yeah, I see what you mean.  I was thinking since tf_tst_ok is
specific to TYPENAME_TYPE handling and isn't propagated (i.e. it only
affects top-level TYPENAME_TYPEs), it seemed cleaner to encode the flag
as a bool parameter "template_ok" of tsubst_typename_type instead of as
a global tsubst_flag that gets propagated freely.

> 
> > In a subsequent patch we'll add another flag to
> > tsubst_typename_type controlling whether we want to ignore non-types
> > during the qualified lookup.

As mentioned above, the second patch in this series would just add
another flag "type_only" alongside "template_ok", since this flag will
also only affects top-level TYPENAME_TYPEs and doesn't need to propagate
like tsubst_flags.

Except, it turns it, this new flag _does_ need to propagate, namely when
expanding a variadic using:

  using typename Ts::type::m...; // from typename25a.C below

Here we have a USING_DECL whose USING_DECL_SCOPE is a
TYPE_PACK_EXPANSION over TYPENAME_TYPE.  In order to correctly
substitute this TYPENAME_TYPE, the USING_DECL case of tsubst_decl needs
to pass an appropriate tsubst_flag to tsubst_pack_expansion to be
propagated to tsubst (to be propagated to make_typename_type).

So in light of this case it seems adding a new tsubst_flag is the
way to go, which means we can avoid this refactoring patch entirely.

Like so?  Bootstrapped and regtested on x86_64-pc-linux-gnu.

-- >8 --

Subject: [PATCH] c++: TYPENAME_TYPE lookup ignoring non-types [PR107773]

Currently when resolving a TYPENAME_TYPE for 'typename T::m' via
make_typename_type, we consider only type bindings of 'm' and ignore
non-type ones.  But [temp.res.general]/3 says, in a note, "the usual
qualified name lookup ([basic.lookup.qual]) applies even in the presence
of 'typename'", and qualified name lookup doesn't discriminate between
type and non-type bindings.  So when resolving such a TYPENAME_TYPE
we want the lookup to consider all bindings.

An exception is when we have a TYPENAME_TYPE corresponding to the
qualifying scope of the :: scope resolution operator, such as
'T::type' in 'typename T::type::m'.  In that case, [basic.lookup.qual]/1
applies, and lookup for such a TYPENAME_TYPE must ignore non-type bindings.
So in order to correctly handle all cases, make_typename_type needs an
additional flag controlling whether lookup should ignore non-types or not.

To that end this patch adds a new tsubst flag tf_qualifying_scope to
communicate to make_typename_type whether we want to ignore non-type
bindings during the lookup (by default we don't want to ignore them).
In contexts where we do want to ignore non-types (when substituting
into the scope of TYPENAME_TYPE, SCOPE_REF or USING_DECL) we simply
pass tf_qualifying_scope to the relevant tsubst / tsubst_copy call.
This flag is intended to apply only to top-level TYPENAME_TYPEs so
we must be careful to clear the flag to avoid propagating it during
substitution of sub-trees.

PR c++/107773

gcc/cp/ChangeLog:

* cp-tree.h (enum tsubst_flags): New flag tf_qualifying_scope.
* decl.cc (make_typename_type): Use lookup_member instead of
lookup_field.  If tf_qualifying_scope is set, pass want_type=true
instead of =false to lookup_member.  Generalize format specifier
in diagnostic to handle both type and non-type bindings.
* pt.cc (tsubst_aggr_type_1): Clear tf_qualifying_scope.  Tidy
the function.
(tsubst_decl) : Set tf_qualifying_scope when
substituting USING_DECL_SCOPE.
(tsubst): Clear tf_qualifying_scope right away and remember if
it was set.  Do the same for tf_tst_ok sooner.
: Set tf_qualifying_scope when substituting
TYPE_CONTEXT.  Pass tf_qualifying_scope to make_typename_type
if it was set.
(tsubst_qualified_id): Set tf_qualifying_scope when substituting
the scope.
(tsubst_copy): Clear tf_qualifying_scope and remember if it was
set.
: Set tf_qualifying_scope when substituting the
scope.
: Pass tf_qualifying_scope

Re: [PATCH 1/2] c++: factor out TYPENAME_TYPE substitution

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

> On 2/15/23 09:21, Patrick Palka wrote:
> > On Tue, 14 Feb 2023, Jason Merrill wrote:
> > 
> > > On 2/13/23 09:23, Patrick Palka wrote:
> > > > [N.B. this is a corrected version of
> > > > https://gcc.gnu.org/pipermail/gcc-patches/2022-November/607443.html ]
> > > > 
> > > > This patch factors out the TYPENAME_TYPE case of tsubst into a separate
> > > > function tsubst_typename_type.  It also factors out the two tsubst flags
> > > > controlling TYPENAME_TYPE substitution, tf_keep_type_decl and tf_tst_ok,
> > > > into distinct boolean parameters of this new function (and of
> > > > make_typename_type).  Consequently, callers which used to pass tf_tst_ok
> > > > to tsubst now instead must directly call tsubst_typename_type when
> > > > appropriate.
> > > 
> > > Hmm, I don't love how that turns 4 lines into 8 more complex lines in each
> > > caller.  And the previous approach of saying "a CTAD placeholder is OK"
> > > seem
> > > like better abstraction than repeating the specific TYPENAME_TYPE handling
> > > in
> > > each place.
> > 
> > Ah yeah, I see what you mean.  I was thinking since tf_tst_ok is
> > specific to TYPENAME_TYPE handling and isn't propagated (i.e. it only
> > affects top-level TYPENAME_TYPEs), it seemed cleaner to encode the flag
> > as a bool parameter "template_ok" of tsubst_typename_type instead of as
> > a global tsubst_flag that gets propagated freely.
> > 
> > > 
> > > > In a subsequent patch we'll add another flag to
> > > > tsubst_typename_type controlling whether we want to ignore non-types
> > > > during the qualified lookup.
> > 
> > As mentioned above, the second patch in this series would just add
> > another flag "type_only" alongside "template_ok", since this flag will
> > also only affects top-level TYPENAME_TYPEs and doesn't need to propagate
> > like tsubst_flags.
> > 
> > Except, it turns it, this new flag _does_ need to propagate, namely when
> > expanding a variadic using:
> > 
> >using typename Ts::type::m...; // from typename25a.C below
> > 
> > Here we have a USING_DECL whose USING_DECL_SCOPE is a
> > TYPE_PACK_EXPANSION over TYPENAME_TYPE.  In order to correctly
> > substitute this TYPENAME_TYPE, the USING_DECL case of tsubst_decl needs
> > to pass an appropriate tsubst_flag to tsubst_pack_expansion to be
> > propagated to tsubst (to be propagated to make_typename_type).
> > 
> > So in light of this case it seems adding a new tsubst_flag is the
> > way to go, which means we can avoid this refactoring patch entirely.
> > 
> > Like so?  Bootstrapped and regtested on x86_64-pc-linux-gnu.
> 
> OK, though I still wonder about adding a tsubst_scope function that would add
> the tf_qualifying_scope.

Hmm, but we need to add tf_qualifying_scope to two tsubst_copy calls,
one tsubst call and one tsubst_aggr_type call (with entering_scope=true).
Would tsubst_scope call tsubst, tsubst_copy or tsubst_aggr_type?

> 
> > -- >8 --
> > 
> > Subject: [PATCH] c++: TYPENAME_TYPE lookup ignoring non-types [PR107773]
> > 
> > Currently when resolving a TYPENAME_TYPE for 'typename T::m' via
> > make_typename_type, we consider only type bindings of 'm' and ignore
> > non-type ones.  But [temp.res.general]/3 says, in a note, "the usual
> > qualified name lookup ([basic.lookup.qual]) applies even in the presence
> > of 'typename'", and qualified name lookup doesn't discriminate between
> > type and non-type bindings.  So when resolving such a TYPENAME_TYPE
> > we want the lookup to consider all bindings.
> > 
> > An exception is when we have a TYPENAME_TYPE corresponding to the
> > qualifying scope of the :: scope resolution operator, such as
> > 'T::type' in 'typename T::type::m'.  In that case, [basic.lookup.qual]/1
> > applies, and lookup for such a TYPENAME_TYPE must ignore non-type bindings.
> > So in order to correctly handle all cases, make_typename_type needs an
> > additional flag controlling whether lookup should ignore non-types or not.
> > 
> > To that end this patch adds a new tsubst flag tf_qualifying_scope to
> > communicate to make_typename_type whether we want to ignore non-type
> > bindings during the lookup (by default we don't want to ignore them).
> > In contexts where we do want to ignore non-types (when substituting
> > into the scope of TYPENAME_TYPE, SCOPE_REF or USING_DECL) we simply
> > pass tf_qualifying_scope to the relevant tsubst / tsubst_copy call.
> > This flag is intended to apply only to top-level TYPENAME_TYPEs so
> > we must be careful to clear the flag to avoid propagating it during
> > substitution of sub-trees.
> > 
> > PR c++/107773
> > 
> > gcc/cp/ChangeLog:
> > 
> > * cp-tree.h (enum tsubst_flags): New flag tf_qualifying_scope.
> > * decl.cc (make_typename_type): Use lookup_member instead of
> > lookup_field.  If tf_qualifying_scope is set, pass want_type=true
> > instead of =false to lookup_member.  Generalize format specifier
> > in diagnostic to handle both type and non-type 

[PATCH] don't declare header-defined functions both static and inline, pt 2

2023-02-16 Thread Patrick Palka via Gcc-patches
This fixes some header-defined functions that are undesirably declared
static and weren't caught by the "^static inline" pattern used in the
previous patch.

gcc/ChangeLog:

* hash-table.h (gt_pch_nx): Remove static.
* lra-int.h (lra_change_class): Likewise.
* recog.h (which_op_alt): Likewise.
* sel-sched-ir.h (sel_bb_empty_or_nop_p): Replace static with
inline.
---
 gcc/hash-table.h   | 2 +-
 gcc/lra-int.h  | 2 +-
 gcc/recog.h| 2 +-
 gcc/sel-sched-ir.h | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/gcc/hash-table.h b/gcc/hash-table.h
index 3f87ec06f37..c0c6e1cd83d 100644
--- a/gcc/hash-table.h
+++ b/gcc/hash-table.h
@@ -1275,7 +1275,7 @@ hashtab_entry_note_pointers (void *obj, void *h, 
gt_pointer_operator op,
 }
 
 template
-static void
+void
 gt_pch_nx (hash_table *h)
 {
   h->check_complete_insertion ();
diff --git a/gcc/lra-int.h b/gcc/lra-int.h
index 73f8eb004b0..a400a0f85e2 100644
--- a/gcc/lra-int.h
+++ b/gcc/lra-int.h
@@ -428,7 +428,7 @@ lra_get_regno_hard_regno (int regno)
 
 /* Change class of pseudo REGNO to NEW_CLASS.  Print info about it
using TITLE.  Output a new line if NL_P.  */
-static void inline
+inline void
 lra_change_class (int regno, enum reg_class new_class,
  const char *title, bool nl_p)
 {
diff --git a/gcc/recog.h b/gcc/recog.h
index 764fa90afde..539a27c3edf 100644
--- a/gcc/recog.h
+++ b/gcc/recog.h
@@ -382,7 +382,7 @@ extern const operand_alternative *recog_op_alt;
on operand OP of the current instruction alternative (which_alternative).
Only valid after calling preprocess_constraints and constrain_operands.  */
 
-inline static const operand_alternative *
+inline const operand_alternative *
 which_op_alt ()
 {
   gcc_checking_assert (IN_RANGE (which_alternative, 0,
diff --git a/gcc/sel-sched-ir.h b/gcc/sel-sched-ir.h
index 7034a1ab06c..0e87134c6db 100644
--- a/gcc/sel-sched-ir.h
+++ b/gcc/sel-sched-ir.h
@@ -1096,7 +1096,7 @@ get_loop_exit_edges_unique_dests (const class loop *loop)
   return edges;
 }
 
-static bool
+inline bool
 sel_bb_empty_or_nop_p (basic_block bb)
 {
   insn_t first = sel_bb_head (bb), last;
-- 
2.39.2.422.gc867e4fa18



Re: [PATCH] c++: ICE with redundant capture [PR108829]

2023-02-17 Thread Patrick Palka via Gcc-patches
On Fri, 17 Feb 2023, Marek Polacek via Gcc-patches wrote:

> Here we crash in is_capture_proxy:
> 
>   /* Location wrappers should be stripped or otherwise handled by the
>  caller before using this predicate.  */
>   gcc_checking_assert (!location_wrapper_p (decl));
> 
> so fixed as the comment suggests.  We only crash with the redundant
> capture:
> 
>   int abyPage = [=, abyPage] { ... }
> 
> because prune_lambda_captures is only called when there was a default
> capture, and with [=] only abyPage won't be in LAMBDA_EXPR_CAPTURE_LIST.

It's weird that we even get this far in var_to_maybe_prune.  Shouldn't
LAMBDA_CAPTURE_EXPLICIT_P be true for abyPage?

> 
> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/12?
> 
>   PR c++/108829
> 
> gcc/cp/ChangeLog:
> 
>   * lambda.cc (var_to_maybe_prune): Strip location wrappers before
>   checking for a capture proxy.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp0x/lambda/lambda-108829.C: New test.
> ---
>  gcc/cp/lambda.cc  |  1 +
>  gcc/testsuite/g++.dg/cpp0x/lambda/lambda-108829.C | 11 +++
>  2 files changed, 12 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-108829.C
> 
> diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc
> index c752622816d..a12b9c183c2 100644
> --- a/gcc/cp/lambda.cc
> +++ b/gcc/cp/lambda.cc
> @@ -1700,6 +1700,7 @@ var_to_maybe_prune (tree cap)
>  return NULL_TREE;
>  
>tree init = TREE_VALUE (cap);
> +  STRIP_ANY_LOCATION_WRAPPER (init);
>if (is_normal_capture_proxy (init))
>  init = DECL_CAPTURED_VARIABLE (init);
>if (decl_constant_var_p (init))
> diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-108829.C 
> b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-108829.C
> new file mode 100644
> index 000..e621a0d14d0
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-108829.C
> @@ -0,0 +1,11 @@
> +// PR c++/108829
> +// { dg-do compile { target c++11 } }
> +
> +template 
> +void f(void) {
> +  constexpr int IDX_PAGE_SIZE = 4096;
> +  int abyPage = [=, abyPage] { return IDX_PAGE_SIZE; }(); // { dg-error 
> "redundant" }
> +}
> +void h() {
> +  f<1>();
> +}
> 
> base-commit: 6245441e124846d0c3551f312d2feef598fe251c
> -- 
> 2.39.2
> 
> 



Re: [PATCH v2] c++: ICE with redundant capture [PR108829]

2023-02-17 Thread Patrick Palka via Gcc-patches
On Fri, 17 Feb 2023, Marek Polacek wrote:

> On Fri, Feb 17, 2023 at 03:00:39PM -0500, Patrick Palka wrote:
> > On Fri, 17 Feb 2023, Marek Polacek via Gcc-patches wrote:
> > 
> > > Here we crash in is_capture_proxy:
> > > 
> > >   /* Location wrappers should be stripped or otherwise handled by the
> > >  caller before using this predicate.  */
> > >   gcc_checking_assert (!location_wrapper_p (decl));
> > > 
> > > so fixed as the comment suggests.  We only crash with the redundant
> > > capture:
> > > 
> > >   int abyPage = [=, abyPage] { ... }
> > > 
> > > because prune_lambda_captures is only called when there was a default
> > > capture, and with [=] only abyPage won't be in LAMBDA_EXPR_CAPTURE_LIST.
> > 
> > It's weird that we even get this far in var_to_maybe_prune.  Shouldn't
> > LAMBDA_CAPTURE_EXPLICIT_P be true for abyPage?
> 
> Ug, I was seduced by the ostensible obviousness and failed to notice
> that check.  In that light, the correct fix ought to be this.  Thanks!
> 
> Bootstrap/regtest running on x86_64-pc-linux-gnu, ok for trunk if it
> passes?
> 
> -- >8 --
> Here we crash in is_capture_proxy:
> 
>   /* Location wrappers should be stripped or otherwise handled by the
>  caller before using this predicate.  */
>   gcc_checking_assert (!location_wrapper_p (decl));
> 
> We only crash with the redundant capture:
> 
>   int abyPage = [=, abyPage] { ... }
> 
> because prune_lambda_captures is only called when there was a default
> capture, and with [=] only abyPage won't be in LAMBDA_EXPR_CAPTURE_LIST.
> 
> The problem is that LAMBDA_CAPTURE_EXPLICIT_P wasn't propagated
> correctly and so var_to_maybe_prune proceeded where it shouldn't.
> 
>   PR c++/108829
> 
> gcc/cp/ChangeLog:
> 
>   * pt.cc (tsubst_lambda_expr): Propagate LAMBDA_CAPTURE_EXPLICIT_P.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp0x/lambda/lambda-108829.C: New test.
> ---
>  gcc/cp/pt.cc  |  4 
>  gcc/testsuite/g++.dg/cpp0x/lambda/lambda-108829.C | 11 +++
>  2 files changed, 15 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-108829.C
> 
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index b1ac7d4beb4..f747ce877b5 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -19992,6 +19992,10 @@ tsubst_lambda_expr (tree t, tree args, 
> tsubst_flags_t complain, tree in_decl)
> if (id_equal (DECL_NAME (field), "__this"))
>   LAMBDA_EXPR_THIS_CAPTURE (r) = field;
>   }
> +
> +  if (LAMBDA_EXPR_CAPTURE_LIST (r))
> + LAMBDA_CAPTURE_EXPLICIT_P (LAMBDA_EXPR_CAPTURE_LIST (r))
> +   = LAMBDA_CAPTURE_EXPLICIT_P (LAMBDA_EXPR_CAPTURE_LIST (t));

I'm not sure how the flag works for pack captures but it looks like
this would only propagate the flag to the last expanded capture if
the capture was originally a pack.

>  }
>  
>tree type = begin_lambda_type (r);
> diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-108829.C 
> b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-108829.C
> new file mode 100644
> index 000..e621a0d14d0
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-108829.C
> @@ -0,0 +1,11 @@
> +// PR c++/108829
> +// { dg-do compile { target c++11 } }
> +
> +template 
> +void f(void) {
> +  constexpr int IDX_PAGE_SIZE = 4096;
> +  int abyPage = [=, abyPage] { return IDX_PAGE_SIZE; }(); // { dg-error 
> "redundant" }
> +}
> +void h() {
> +  f<1>();
> +}
> 
> base-commit: 5fea1be820508e1fbc610d1a54b61c1add33c36f
> -- 
> 2.39.2
> 
> 



Re: [PATCH v2] c++: ICE with redundant capture [PR108829]

2023-02-17 Thread Patrick Palka via Gcc-patches
On Fri, 17 Feb 2023, Patrick Palka wrote:

> On Fri, 17 Feb 2023, Marek Polacek wrote:
> 
> > On Fri, Feb 17, 2023 at 03:00:39PM -0500, Patrick Palka wrote:
> > > On Fri, 17 Feb 2023, Marek Polacek via Gcc-patches wrote:
> > > 
> > > > Here we crash in is_capture_proxy:
> > > > 
> > > >   /* Location wrappers should be stripped or otherwise handled by the
> > > >  caller before using this predicate.  */
> > > >   gcc_checking_assert (!location_wrapper_p (decl));
> > > > 
> > > > so fixed as the comment suggests.  We only crash with the redundant
> > > > capture:
> > > > 
> > > >   int abyPage = [=, abyPage] { ... }
> > > > 
> > > > because prune_lambda_captures is only called when there was a default
> > > > capture, and with [=] only abyPage won't be in LAMBDA_EXPR_CAPTURE_LIST.
> > > 
> > > It's weird that we even get this far in var_to_maybe_prune.  Shouldn't
> > > LAMBDA_CAPTURE_EXPLICIT_P be true for abyPage?
> > 
> > Ug, I was seduced by the ostensible obviousness and failed to notice
> > that check.  In that light, the correct fix ought to be this.  Thanks!
> > 
> > Bootstrap/regtest running on x86_64-pc-linux-gnu, ok for trunk if it
> > passes?
> > 
> > -- >8 --
> > Here we crash in is_capture_proxy:
> > 
> >   /* Location wrappers should be stripped or otherwise handled by the
> >  caller before using this predicate.  */
> >   gcc_checking_assert (!location_wrapper_p (decl));
> > 
> > We only crash with the redundant capture:
> > 
> >   int abyPage = [=, abyPage] { ... }
> > 
> > because prune_lambda_captures is only called when there was a default
> > capture, and with [=] only abyPage won't be in LAMBDA_EXPR_CAPTURE_LIST.
> > 
> > The problem is that LAMBDA_CAPTURE_EXPLICIT_P wasn't propagated
> > correctly and so var_to_maybe_prune proceeded where it shouldn't.
> > 
> > PR c++/108829
> > 
> > gcc/cp/ChangeLog:
> > 
> > * pt.cc (tsubst_lambda_expr): Propagate LAMBDA_CAPTURE_EXPLICIT_P.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/cpp0x/lambda/lambda-108829.C: New test.
> > ---
> >  gcc/cp/pt.cc  |  4 
> >  gcc/testsuite/g++.dg/cpp0x/lambda/lambda-108829.C | 11 +++
> >  2 files changed, 15 insertions(+)
> >  create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-108829.C
> > 
> > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > index b1ac7d4beb4..f747ce877b5 100644
> > --- a/gcc/cp/pt.cc
> > +++ b/gcc/cp/pt.cc
> > @@ -19992,6 +19992,10 @@ tsubst_lambda_expr (tree t, tree args, 
> > tsubst_flags_t complain, tree in_decl)
> >   if (id_equal (DECL_NAME (field), "__this"))
> > LAMBDA_EXPR_THIS_CAPTURE (r) = field;
> > }
> > +
> > +  if (LAMBDA_EXPR_CAPTURE_LIST (r))
> > +   LAMBDA_CAPTURE_EXPLICIT_P (LAMBDA_EXPR_CAPTURE_LIST (r))
> > + = LAMBDA_CAPTURE_EXPLICIT_P (LAMBDA_EXPR_CAPTURE_LIST (t));
> 
> I'm not sure how the flag works for pack captures but it looks like
> this would only propagate the flag to the last expanded capture if
> the capture was originally a pack.

Testcase:

  template
  void f(Ts... ts) {
constexpr int IDX_PAGE_SIZE = 4096;
int abyPage = [=, ts...] { return IDX_PAGE_SIZE; }();
  }
  void h() {
f<1>(0, 1);
  }

> 
> >  }
> >  
> >tree type = begin_lambda_type (r);
> > diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-108829.C 
> > b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-108829.C
> > new file mode 100644
> > index 000..e621a0d14d0
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-108829.C
> > @@ -0,0 +1,11 @@
> > +// PR c++/108829
> > +// { dg-do compile { target c++11 } }
> > +
> > +template 
> > +void f(void) {
> > +  constexpr int IDX_PAGE_SIZE = 4096;
> > +  int abyPage = [=, abyPage] { return IDX_PAGE_SIZE; }(); // { dg-error 
> > "redundant" }
> > +}
> > +void h() {
> > +  f<1>();
> > +}
> > 
> > base-commit: 5fea1be820508e1fbc610d1a54b61c1add33c36f
> > -- 
> > 2.39.2
> > 
> > 
> 



Re: [PATCH RFC 1/3] c++: add __is_deducible trait [PR105841]

2023-02-20 Thread Patrick Palka via Gcc-patches
On Sat, 18 Feb 2023, Jason Merrill via Gcc-patches wrote:

> Tested x86_64-pc-linux-gnu.  Since this is fixing experimental (C++20)
> functionality, I think it's reasonable to apply now; I'm interested in other
> opinions, and thoughts about the user-facing functionality.  I'm thinking to
> make it internal-only for GCC 13 at least by adding a space in the name, but
> does this look useful to the library?

IIUC this looks like a generalization of an __is_specialization_of trait
that returns whether a type is a specialization of a given class template,
which seems potentially useful for the library to me.  We already define
some ad-hoc predicates for testing this, e.g. __is_reverse_view,
__is_span etc in  as well as a more general __is_specialization_of
in  for templates that take only type arguments.  Using a built-in
trait should be more efficient.

> 
> -- 8< --
> 
> C++20 class template argument deduction for an alias template involves
> adding a constraint that the template arguments for the alias template can
> be deduced from the return type of the deduction guide for the underlying
> class template.  In the standard, this is modeled as defining a class
> template with a partial specialization, but it's much more efficient to
> implement with a trait that directly tries to perform the deduction.
> 
> The first argument to the trait is a template rather than a type, so various
> places needed to be adjusted to accommodate that.
> 
>   PR c++/105841
> 
> gcc/ChangeLog:
> 
>   * doc/extend.texi (Type Traits):: Document __is_deducible.
> 
> gcc/cp/ChangeLog:
> 
>   * cp-trait.def (IS_DEDUCIBLE): New.
>   * cxx-pretty-print.cc (pp_cxx_trait): Handle non-type.
>   * parser.cc (cp_parser_trait): Likewise.
>   * pt.cc (tsubst_copy_and_build): Likewise.
>   (type_targs_deducible_from): New.
>   (alias_ctad_tweaks): Use it.
>   * semantics.cc (trait_expr_value): Handle CPTK_IS_DEDUCIBLE.
>   (finish_trait_expr): Likewise.
>   * constraint.cc (diagnose_trait_expr): Likewise.
>   * cp-tree.h (type_targs_deducible_from): Declare.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/ext/is_deducible1.C: New test.
> ---
>  gcc/doc/extend.texi  |  4 +++
>  gcc/cp/cp-tree.h |  1 +
>  gcc/cp/constraint.cc |  3 ++
>  gcc/cp/cxx-pretty-print.cc   |  5 +++-
>  gcc/cp/parser.cc | 20 +++---
>  gcc/cp/pt.cc | 35 +---
>  gcc/cp/semantics.cc  | 11 
>  gcc/testsuite/g++.dg/ext/is_deducible1.C | 27 ++
>  gcc/cp/cp-trait.def  |  1 +
>  9 files changed, 92 insertions(+), 15 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_deducible1.C
> 
> diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
> index 1ae68b0f20a..898701424ad 100644
> --- a/gcc/doc/extend.texi
> +++ b/gcc/doc/extend.texi
> @@ -25207,6 +25207,10 @@ type.  A diagnostic is produced if this requirement 
> is not met.
>  If @code{type} is a cv-qualified class type, and not a union type
>  ([basic.compound]) the trait is @code{true}, else it is @code{false}.
>  
> +@item __is_deducible (template, type)
> +If template arguments for @code{template} can be deduced from
> +@code{type} or obtained from default template arguments.
> +
>  @item __is_empty (type)
>  If @code{__is_class (type)} is @code{false} then the trait is @code{false}.
>  Otherwise @code{type} is considered empty if and only if: @code{type}
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 5595335bbf7..e79150ca4d8 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -7372,6 +7372,7 @@ extern tree fn_type_unification (tree, 
> tree, tree,
>bool, bool);
>  extern void mark_decl_instantiated   (tree, int);
>  extern int more_specialized_fn   (tree, tree, int);
> +extern bool type_targs_deducible_from(tree, tree);
>  extern void do_decl_instantiation(tree, tree);
>  extern void do_type_instantiation(tree, tree, tsubst_flags_t);
>  extern bool always_instantiate_p (tree);
> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> index 9374327008b..a28c85178fe 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -3797,6 +3797,9 @@ diagnose_trait_expr (tree expr, tree args)
>inform (loc, "  %qT is not a reference that binds to a temporary "
> "object of type %qT (copy-initialization)", t1, t2);
>break;
> +case CPTK_IS_DEDUCIBLE:
> +  inform (loc, "  %qD is not deducible from %qT", t1, t2);
> +  break;
>  #define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
>  case CPTK_##CODE:
>  #include "cp-trait.def"
> diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc
> index bea52a608f1..4ebd957decd 100644
> --- a/gcc/cp

[PATCH] c++: constant non-copy-init is manifestly constant [PR108243]

2023-02-20 Thread Patrick Palka via Gcc-patches
According to [basic.start.static]/2 and [expr.const]/2, a variable
with static storage duration initialized with a constant initializer
has constant initialization, and such an initializer is manifestly
constant-evaluated.

We're already getting this right with copy initialization because in
that case check_initializer would consistently call store_init_value
(which for TREE_STATIC variables calls fold_non_dependent_init with
m_c_e=true).

But for direct (or default) initialization, we don't always call
store_init_value.  We instead however always call maybe_constant_init
from expand_default_init[1], albeit with m_c_e=false which means we
don't always get the "manifestly constant-evaluated" part right for
copy-init.

This patch fixes this by simply passing m_c_e=true to this call to
maybe_constant_init for static storage duration variables, mirroring
what store_init_value basically does.

[1]: this maybe_constant_init call isn't reached in the copy-init
case because there init is a CONSTRUCTOR rather than a TREE_LIST so
expand_default_init exits early returning an INIT_EXPR.  This INIT_EXPR
is ultimately what causes us to consistently hit the store_init_value
code path from check_initializer in the copy-init case.

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?  Would it be suitable to backport this to the 12 branch since
it should only affect C++20 code?

PR c++/108243

gcc/cp/ChangeLog:

* init.cc (expand_default_init): Pass m_c_e=true instead of
=false to maybe_constant_init when initializing a variable
with static storage duration.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/is-constant-evaluated14.C: New test.
---
 gcc/cp/init.cc|   5 +-
 .../g++.dg/cpp2a/is-constant-evaluated14.C| 140 ++
 2 files changed, 144 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated14.C

diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index 52e96fbe590..705a5b3bdb6 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -2203,7 +2203,10 @@ expand_default_init (tree binfo, tree true_exp, tree 
exp, tree init, int flags,
   tree fn = get_callee_fndecl (rval);
   if (fn && DECL_DECLARED_CONSTEXPR_P (fn))
{
- tree e = maybe_constant_init (rval, exp);
+ bool manifestly_const_eval = false;
+ if (VAR_P (exp) && TREE_STATIC (exp))
+   manifestly_const_eval = true;
+ tree e = maybe_constant_init (rval, exp, manifestly_const_eval);
  if (TREE_CONSTANT (e))
rval = cp_build_init_expr (exp, e);
}
diff --git a/gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated14.C 
b/gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated14.C
new file mode 100644
index 000..365bca3fd9a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated14.C
@@ -0,0 +1,140 @@
+// PR c++/108243
+// Verify a variable with static storage duration initialized with a
+// constant initializer has constant initialization, and the initializer
+// is manifestly constant-evaluated.
+// { dg-do run { target c++11 } }
+// { dg-additional-options "-fdump-tree-original" }
+
+#include 
+
+struct A {
+  constexpr A(int n) : n(n), m(__builtin_is_constant_evaluated()) { }
+  constexpr A() : A(42) { }
+  void verify_mce() const {
+if (m != 1) __builtin_abort();
+  }
+  int n;
+  int m;
+};
+
+A a1 = {42};
+A a2{42};
+A a3(42);
+A a4;
+A a5{};
+
+void f() {
+  static A a1 = {42};
+  static A a2{42};
+  static A a3(42);
+  static A a4;
+  static A a5{};
+  for (auto& a : {a1, a2, a3, a4, a5})
+a.verify_mce();
+}
+
+template
+void g() {
+  static A a1 = {42};
+  static A a2{42};
+  static A a3(42);
+  static A a4;
+  static A a5{};
+  static A a6 = {N...};
+  static A a7{N...};
+  static A a8(N...);
+  for (auto& a : {a1, a2, a3, a4, a5, a6, a7, a8})
+a.verify_mce();
+}
+
+struct B {
+  static A a1;
+  static A a2;
+  static A a3;
+  static A a4;
+  static A a5;
+  static void verify_mce() {
+for (auto& a : {a1, a2, a3, a4, a5})
+  a.verify_mce();
+  }
+};
+
+A B::a1 = {42};
+A B::a2{42};
+A B::a3(42);
+A B::a4;
+A B::a5{};
+
+template
+struct BT {
+  static A a1;
+  static A a2;
+  static A a3;
+  static A a4;
+  static A a5;
+  static A a6;
+  static A a7;
+  static A a8;
+  static void verify_mce() {
+for (auto& a : {a1, a2, a3, a4, a5})
+  a.verify_mce();
+  }
+};
+
+template A BT::a1 = {42};
+template A BT::a2{42};
+template A BT::a3(42);
+template A BT::a4;
+template A BT::a5{};
+template A BT::a6 = {N...};
+template A BT::a7{N...};
+template A BT::a8(N...);
+
+#if __cpp_inline_variables
+struct BI {
+  static inline A a1 = {42};
+  static inline A a2{42};
+  static inline A a3;
+  static inline A a4{};
+  static void verify_mce() {
+for (auto& a : {a1, a2, a3, a4})
+  a.verify_mce();
+  }
+};
+
+template
+struct BIT {
+  static inline A a1 = {42};
+  static inline A a2{42};
+  static inline A 

  1   2   3   4   5   6   7   8   9   10   >