public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/users/jason/heads/alias-ctad)] c++: add __is_deducible trait
@ 2023-02-09 23:01 Jason Merrill
  0 siblings, 0 replies; only message in thread
From: Jason Merrill @ 2023-02-09 23:01 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:b0befb1a6f5efd8c5e60f6c976d55b0e14e9c479

commit b0befb1a6f5efd8c5e60f6c976d55b0e14e9c479
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Feb 9 12:51:51 2023 -0800

    c++: add __is_deducible trait
    
    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.
    
    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.

Diff:
---
 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                         | 14 +++++++++----
 gcc/cp/pt.cc                             | 35 +++++++++++++++++++++++---------
 gcc/cp/semantics.cc                      |  8 ++++++++
 gcc/testsuite/g++.dg/ext/is_deducible1.C | 15 ++++++++++++++
 gcc/cp/cp-trait.def                      |  1 +
 9 files changed, 71 insertions(+), 15 deletions(-)

diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 5a026c4b48c..d74199fa7b3 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 31fd8af4f21..d301c390d5d 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7369,6 +7369,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 2e5acdf8fcb..ab893580ae9 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3798,6 +3798,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/cxx-pretty-print.cc
+++ b/gcc/cp/cxx-pretty-print.cc
@@ -2626,7 +2626,10 @@ pp_cxx_trait (cxx_pretty_printer *pp, tree t)
     }
 
   pp_cxx_left_paren (pp);
-  pp->type_id (type1);
+  if (DECL_P (type1))
+    pp->expression (type1);
+  else
+    pp->type_id (type1);
   if (type2)
     {
       if (TREE_CODE (type2) != TREE_LIST)
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 4cdc1cd472f..d0be004d460 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -10960,10 +10960,16 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
   matching_parens parens;
   parens.require_open (parser);
 
-  {
-    type_id_in_expr_sentinel s (parser);
-    type1 = cp_parser_type_id (parser);
-  }
+  if (kind == CPTK_IS_DEDUCIBLE)
+    {
+      type1 = cp_parser_template_name (parser, false, true, false,
+				       none_type, nullptr);
+    }
+  else
+    {
+      type_id_in_expr_sentinel s (parser);
+      type1 = cp_parser_type_id (parser);
+    }
 
   if (type1 == error_mark_node)
     return error_mark_node;
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 51fc246ed71..497ecd7cbaa 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -21571,8 +21571,9 @@ tsubst_copy_and_build (tree t,
 
     case TRAIT_EXPR:
       {
-	tree type1 = tsubst (TRAIT_EXPR_TYPE1 (t), args,
-			     complain, in_decl);
+	tree type1 = TRAIT_EXPR_TYPE1 (t);
+	if (TREE_CODE (type1) != TEMPLATE_DECL)
+	  type1 = tsubst (type1, args, complain, in_decl);
 	tree type2 = tsubst (TRAIT_EXPR_TYPE2 (t), args,
 			     complain, in_decl);
 	RETURN (finish_trait_expr (TRAIT_EXPR_LOCATION (t),
@@ -29973,7 +29974,7 @@ alias_ctad_tweaks (tree tmpl, tree uguides)
   /* This implementation differs from the above in two significant ways:
 
      1) We include all template parameters of A, not just some.
-     2) The added constraint is same_type instead of deducible.
+     2) [fixed] The added constraint is same_type instead of deducible.
 
      I believe that while it's probably possible to construct a testcase that
      behaves differently with this simplification, it should have the same
@@ -30073,7 +30074,7 @@ alias_ctad_tweaks (tree tmpl, tree uguides)
 	      /* FIXME this should mean they don't compare as equivalent.  */
 	      || dependent_alias_template_spec_p (atype, nt_opaque))
 	    {
-	      tree same = finish_trait_expr (loc, CPTK_IS_SAME, atype, ret);
+	      tree same = finish_trait_expr (loc, CPTK_IS_DEDUCIBLE, tmpl, ret);
 	      ci = append_constraint (ci, same);
 	    }
 
@@ -30087,12 +30088,7 @@ alias_ctad_tweaks (tree tmpl, tree uguides)
 	{
 	  /* For a non-template deduction guide, if the arguments of A aren't
 	     deducible from the return type, don't add the candidate.  */
-	  tree targs = make_tree_vec (natparms);
-	  int err = unify (atparms, targs, utype, ret, UNIFY_ALLOW_NONE, false);
-	  for (unsigned i = 0; !err && i < natparms; ++i)
-	    if (TREE_VEC_ELT (targs, i) == NULL_TREE)
-	      err = true;
-	  if (err)
+	  if (!type_targs_deducible_from (tmpl, ret))
 	    continue;
 	}
 
@@ -30102,6 +30098,25 @@ alias_ctad_tweaks (tree tmpl, tree uguides)
   return aguides;
 }
 
+/* True iff template arguments for TMPL can be deduced from TYPE.
+   Used to implement CPTK_IS_DEDUCIBLE for alias CTAD.  */
+
+bool
+type_targs_deducible_from (tree tmpl, tree type)
+{
+  tree tparms = DECL_INNERMOST_TEMPLATE_PARMS (tmpl);
+  int len = TREE_VEC_LENGTH (tparms);
+  tree targs = make_tree_vec (len);
+  if (unify (tparms, targs, TREE_TYPE (tmpl), type,
+	     UNIFY_ALLOW_NONE, false))
+    return false;
+  /* Maybe add in default template args.  */
+  targs = coerce_template_parms (tparms, targs, tmpl, tf_none);
+  if (targs == error_mark_node)
+    return false;
+  return constraints_satisfied_p (tmpl, targs);
+}
+
 /* Return artificial deduction guides built from the constructors of class
    template TMPL.  */
 
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 1656d02d6d1..6e1aae07fbb 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12040,6 +12040,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_REF_CONVERTS_FROM_TEMPORARY:
       return ref_xes_from_temporary (type1, type2, /*direct_init=*/false);
 
+    case CPTK_IS_DEDUCIBLE:
+      return type_targs_deducible_from (type1, type2);
+
 #define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
     case CPTK_##CODE:
 #include "cp-trait.def"
@@ -12197,6 +12200,11 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_DEDUCIBLE:
+      if (!DECL_TYPE_TEMPLATE_P (type1))
+	return error_mark_node;
+      break;
+
 #define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
     case CPTK_##CODE:
 #include "cp-trait.def"
diff --git a/gcc/testsuite/g++.dg/ext/is_deducible1.C b/gcc/testsuite/g++.dg/ext/is_deducible1.C
new file mode 100644
index 00000000000..b2aa4cea084
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_deducible1.C
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++20 } }
+
+template <class T> struct A { };
+template <class T> struct B { };
+
+static_assert (__is_deducible (A, A<int>));
+static_assert (__is_deducible (B, B<int>));
+static_assert (!__is_deducible (A, B<int>));
+static_assert (!__is_deducible (B, A<int>));
+
+template <class T> using C = void;
+static_assert (!__is_deducible (C, C<int>));
+
+template <class T = void> using D = void;
+static_assert (__is_deducible (D, D<int>));
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 823899a26c5..e43fb464f42 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -84,6 +84,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
+DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible", 2)
 
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
 DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2023-02-09 23:01 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-02-09 23:01 [gcc(refs/users/jason/heads/alias-ctad)] c++: add __is_deducible trait Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).