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/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 1a124f5395e..68950cace78 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -10960,10 +10960,22 @@ 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)
+    {
+      const cp_token* token = cp_lexer_peek_token (parser->lexer);
+      type1 = cp_parser_id_expression (parser,
+				       /*template_keyword_p=*/false,
+				       /*check_dependency_p=*/true,
+				       nullptr,
+				       /*declarator_p=*/false,
+				       /*optional_p=*/false);
+      type1 = cp_parser_lookup_name_simple (parser, type1, token->location);
+    }
+  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 b1ac7d4beb4..2aa06557b99 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -21577,8 +21577,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),
@@ -29979,7 +29980,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
@@ -30079,7 +30080,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);
 	    }
 
@@ -30093,12 +30094,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;
 	}
 
@@ -30108,6 +30104,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 79b7cc72f21..9103f5de2f4 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12048,6 +12048,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"
@@ -12205,6 +12208,14 @@ 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))
+	{
+	  error ("%qD is not a class or alias template", 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..857f59db4c8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_deducible1.C
@@ -0,0 +1,27 @@
+// { dg-do compile { target c++20 } }
+
+template <class T> struct A { };
+template <class T> struct B { };
+
+// Simple forms.
+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>));
+
+// This is the interesting use case for alias CTAD.
+template <class T> using AP = A<T*>;
+static_assert (__is_deducible (AP, A<int*>));
+static_assert (!__is_deducible (AP, A<int>));
+
+// Can't deduce a parameter not used on the RHS.
+template <class T> using C = void;
+static_assert (!__is_deducible (C, C<int>));
+
+// But a default template argument counts.
+template <class T = void> using D = void;
+static_assert (__is_deducible (D, D<int>));
+
+// We don't try to support this.
+template <class T> void f(T);
+bool b = __is_deducible (f, void (int)); // { dg-error "class or alias" }
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)
