--- gcc/c-family/c-common.h.jj	2021-07-21 18:55:05.239627937 +0200
+++ gcc/c-family/c-common.h	2021-07-28 12:07:31.717700448 +0200
@@ -174,6 +174,7 @@ enum rid
   RID_IS_BASE_OF,              RID_IS_CLASS,
   RID_IS_EMPTY,                RID_IS_ENUM,
   RID_IS_FINAL,                RID_IS_LITERAL_TYPE,
+  RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF,
   RID_IS_POD,                  RID_IS_POLYMORPHIC,
   RID_IS_SAME_AS,
   RID_IS_STD_LAYOUT,           RID_IS_TRIVIAL,
--- gcc/c-family/c-common.c.jj	2021-07-21 18:55:05.239627937 +0200
+++ gcc/c-family/c-common.c	2021-07-28 12:08:26.419963865 +0200
@@ -421,6 +421,8 @@ const struct c_common_resword c_common_r
   { "__is_enum",	RID_IS_ENUM,	D_CXXONLY },
   { "__is_final",	RID_IS_FINAL,	D_CXXONLY },
   { "__is_literal_type", RID_IS_LITERAL_TYPE, D_CXXONLY },
+  { "__is_pointer_interconvertible_base_of",
+			RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF, D_CXXONLY },
   { "__is_pod",		RID_IS_POD,	D_CXXONLY },
   { "__is_polymorphic",	RID_IS_POLYMORPHIC, D_CXXONLY },
   { "__is_same",     RID_IS_SAME_AS, D_CXXONLY },
--- gcc/cp/cp-tree.h.jj	2021-07-21 18:55:05.326626722 +0200
+++ gcc/cp/cp-tree.h	2021-07-28 14:08:55.920562235 +0200
@@ -1366,6 +1366,7 @@ enum cp_trait_kind
   CPTK_IS_ENUM,
   CPTK_IS_FINAL,
   CPTK_IS_LITERAL_TYPE,
+  CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF,
   CPTK_IS_POD,
   CPTK_IS_POLYMORPHIC,
   CPTK_IS_SAME_AS,
@@ -6355,6 +6356,7 @@ struct GTY((chain_next ("%h.next"))) tin
 enum cp_built_in_function {
   CP_BUILT_IN_IS_CONSTANT_EVALUATED,
   CP_BUILT_IN_INTEGER_PACK,
+  CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS,
   CP_BUILT_IN_SOURCE_LOCATION,
   CP_BUILT_IN_LAST
 };
@@ -7570,6 +7572,7 @@ extern tree baselink_for_fns
 extern void finish_static_assert                (tree, tree, location_t,
 						 bool, bool);
 extern tree finish_decltype_type                (tree, bool, tsubst_flags_t);
+extern tree fold_builtin_is_pointer_inverconvertible_with_class (location_t, int, tree *);
 extern tree finish_trait_expr			(location_t, enum cp_trait_kind, tree, tree);
 extern tree build_lambda_expr                   (void);
 extern tree build_lambda_object			(tree);
--- gcc/cp/parser.c.jj	2021-07-27 09:47:44.098780350 +0200
+++ gcc/cp/parser.c	2021-07-28 12:10:24.669370137 +0200
@@ -5797,6 +5797,7 @@ cp_parser_primary_expression (cp_parser
 	case RID_IS_ENUM:
 	case RID_IS_FINAL:
 	case RID_IS_LITERAL_TYPE:
+	case RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
 	case RID_IS_POD:
 	case RID_IS_POLYMORPHIC:
 	case RID_IS_SAME_AS:
@@ -10686,6 +10687,10 @@ cp_parser_trait_expr (cp_parser* parser,
     case RID_IS_LITERAL_TYPE:
       kind = CPTK_IS_LITERAL_TYPE;
       break;
+    case RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
+      kind = CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF;
+      binary = true;
+      break;
     case RID_IS_POD:
       kind = CPTK_IS_POD;
       break;
--- gcc/cp/cp-objcp-common.c.jj	2021-07-21 18:55:05.301627072 +0200
+++ gcc/cp/cp-objcp-common.c	2021-07-28 12:10:40.358158672 +0200
@@ -414,6 +414,7 @@ names_builtin_p (const char *name)
     case RID_IS_ENUM:
     case RID_IS_FINAL:
     case RID_IS_LITERAL_TYPE:
+    case RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
     case RID_IS_POD:
     case RID_IS_POLYMORPHIC:
     case RID_IS_SAME_AS:
--- gcc/cp/constraint.cc.jj	2021-07-21 18:55:05.281627351 +0200
+++ gcc/cp/constraint.cc	2021-07-28 12:12:31.875655576 +0200
@@ -3631,6 +3631,10 @@ diagnose_trait_expr (tree expr, tree arg
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
+      inform (loc, "  %qT is not pointer-interconvertible base of %qT",
+	      t1, t2);
+      break;
     case CPTK_IS_POD:
       inform (loc, "  %qT is not a POD type", t1);
       break;
--- gcc/cp/decl.c.jj	2021-07-21 18:55:05.362626220 +0200
+++ gcc/cp/decl.c	2021-07-28 13:35:55.640239697 +0200
@@ -4467,6 +4467,15 @@ cxx_init_decl_processing (void)
 			       BUILT_IN_FRONTEND, NULL, NULL_TREE);
   set_call_expr_flags (decl, ECF_CONST | ECF_NOTHROW | ECF_LEAF);
 
+  tree bool_vaftype = build_varargs_function_type_list (boolean_type_node,
+							NULL_TREE);
+  decl
+    = add_builtin_function ("__builtin_is_pointer_interconvertible_with_class",
+			    bool_vaftype,
+			    CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS,
+			    BUILT_IN_FRONTEND, NULL, NULL_TREE);
+  set_call_expr_flags (decl, ECF_CONST | ECF_NOTHROW | ECF_LEAF);
+
   integer_two_node = build_int_cst (NULL_TREE, 2);
 
   /* Guess at the initial static decls size.  */
--- gcc/cp/constexpr.c.jj	2021-07-21 18:55:05.256627699 +0200
+++ gcc/cp/constexpr.c	2021-07-28 17:12:01.796428596 +0200
@@ -1427,8 +1427,20 @@ cxx_eval_builtin_function_call (const co
       && ctx->call
       && ctx->call->fundef)
     current_function_decl = ctx->call->fundef->decl;
-  new_call = fold_builtin_call_array (EXPR_LOCATION (t), TREE_TYPE (t),
-				      CALL_EXPR_FN (t), nargs, args);
+  if (fndecl_built_in_p (fun,
+			 CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS,
+			 BUILT_IN_FRONTEND))
+    {
+      location_t loc = EXPR_LOCATION (t);
+      if (nargs >= 1)
+	VERIFY_CONSTANT (args[0]);
+      new_call
+	= fold_builtin_is_pointer_inverconvertible_with_class (loc, nargs,
+							       args);
+    }
+  else
+    new_call = fold_builtin_call_array (EXPR_LOCATION (t), TREE_TYPE (t),
+					CALL_EXPR_FN (t), nargs, args);
   current_function_decl = save_cur_fn;
   force_folding_builtin_constant_p = save_ffbcp;
   if (new_call == NULL)
--- gcc/cp/semantics.c.jj	2021-07-22 12:37:20.450532703 +0200
+++ gcc/cp/semantics.c	2021-07-28 16:51:05.119363473 +0200
@@ -10566,6 +10566,135 @@ classtype_has_nothrow_assign_or_copy_p (
   return saw_copy;
 }
 
+/* Helper function for pointer_interconvertible_base_of_p.  Verify
+   that BINFO_TYPE (BINFO) is pointer interconvertible with BASE.  */
+
+static bool
+pointer_interconvertible_base_of_p_1 (tree binfo, tree base)
+{
+  for (tree field = TYPE_FIELDS (BINFO_TYPE (binfo));
+       field; field = DECL_CHAIN (field))
+    if (TREE_CODE (field) == FIELD_DECL && !DECL_FIELD_IS_BASE (field))
+      return false;
+
+  unsigned ix;
+  tree base_binfo;
+  for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ix++)
+    if (SAME_BINFO_TYPE_P (BINFO_TYPE (base_binfo), base)
+	|| pointer_interconvertible_base_of_p_1 (base_binfo, base))
+      return true;
+  return false;
+}
+
+/* Return true if DERIVED is pointer interconvertible base of BASE.  */
+
+static bool
+pointer_interconvertible_base_of_p (tree base, tree derived)
+{
+  if (base == error_mark_node || derived == error_mark_node)
+    return false;
+  base = cp_build_qualified_type (base, TYPE_UNQUALIFIED);
+  derived = cp_build_qualified_type (derived, TYPE_UNQUALIFIED);
+  if (NON_UNION_CLASS_TYPE_P (base)
+      && NON_UNION_CLASS_TYPE_P (derived)
+      && same_type_p (base, derived))
+    return true;
+
+  if (!complete_type_or_else (derived, NULL_TREE))
+    return false;
+
+  if (!uniquely_derived_from_p (base, derived))
+    return false;
+
+  if (!std_layout_type_p (derived))
+    return false;
+
+  return pointer_interconvertible_base_of_p_1 (TYPE_BINFO (derived), base);
+}
+
+/* Helper function for fold_builtin_is_pointer_inverconvertible_with_class,
+   return true if MEMBERTYPE is the type of the first non-static data member
+   of TYPE or for unions of any members.  */
+static bool
+first_nonstatic_data_member_p (tree type, tree membertype)
+{
+  for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+    {
+      if (TREE_CODE (field) != FIELD_DECL)
+	continue;
+      if (DECL_FIELD_IS_BASE (field) && is_empty_field (field))
+	continue;
+      if (DECL_FIELD_IS_BASE (field))
+	return first_nonstatic_data_member_p (TREE_TYPE (field), membertype);
+      if (ANON_AGGR_TYPE_P (TREE_TYPE (field)))
+	{
+	  if (TREE_CODE (type) != UNION_TYPE)
+	    return first_nonstatic_data_member_p (TREE_TYPE (field),
+						  membertype);
+	  if (first_nonstatic_data_member_p (TREE_TYPE (field), membertype))
+	    return true;
+	}
+      else if (TREE_CODE (type) != UNION_TYPE)
+	return same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (field),
+							  membertype);
+      else if (same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (field),
+							  membertype))
+	return true;
+    }
+  return false;
+}
+
+/* Fold __builtin_is_pointer_interconvertible_with_class call.  */
+
+tree
+fold_builtin_is_pointer_inverconvertible_with_class (location_t loc, int nargs,
+						     tree *args)
+{
+  /* Unless users call the builtin directly, the following 3 checks should be
+     ensured from std::is_pointer_interconvertible_with_class function
+     template.  */
+  if (nargs != 1)
+    {
+      error_at (loc, "%<__builtin_is_pointer_interconvertible_with_class%> "
+		     "needs a single argument");
+      return boolean_false_node;
+    }
+  tree arg = args[0];
+  if (error_operand_p (arg))
+    return boolean_false_node;
+  if (!TYPE_PTRMEM_P (TREE_TYPE (arg)))
+    {
+      error_at (loc, "%<__builtin_is_pointer_interconvertible_with_class%> "
+		     "argument is not pointer to member");
+      return boolean_false_node;
+    }
+
+  if (!TYPE_PTRDATAMEM_P (TREE_TYPE (arg)))
+    return boolean_false_node;
+
+  tree membertype = TREE_TYPE (TREE_TYPE (arg));
+  tree basetype = TYPE_OFFSET_BASETYPE (TREE_TYPE (arg));
+  if (!complete_type_or_else (basetype, NULL_TREE))
+    return boolean_false_node;
+
+  if (!std_layout_type_p (basetype))
+    return boolean_false_node;
+
+  if (!first_nonstatic_data_member_p (basetype, membertype))
+    return boolean_false_node;
+
+  if (TREE_CODE (arg) == PTRMEM_CST)
+    arg = cplus_expand_constant (arg);
+
+  if (integer_nonzerop (arg))
+    return boolean_false_node;
+  if (integer_zerop (arg))
+    return boolean_true_node;
+
+  return fold_build2 (EQ_EXPR, boolean_type_node, arg,
+		      build_zero_cst (TREE_TYPE (arg)));
+}
+
 /* Actually evaluates the trait.  */
 
 static bool
@@ -10659,6 +10788,9 @@ trait_expr_value (cp_trait_kind kind, tr
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
+      return pointer_interconvertible_base_of_p (type1, type2);
+
     case CPTK_IS_POD:
       return pod_type_p (type1);
 
@@ -10786,6 +10918,7 @@ finish_trait_expr (location_t loc, cp_tr
       break;
 
     case CPTK_IS_BASE_OF:
+    case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       if (NON_UNION_CLASS_TYPE_P (type1) && NON_UNION_CLASS_TYPE_P (type2)
 	  && !same_type_ignoring_top_level_qualifiers_p (type1, type2)
 	  && !complete_type_or_else (type2, NULL_TREE))
@@ -10803,9 +10936,9 @@ finish_trait_expr (location_t loc, cp_tr
       gcc_unreachable ();
     }
 
-tree val = (trait_expr_value (kind, type1, type2)
-	    ? boolean_true_node : boolean_false_node);
- return maybe_wrap_with_location (val, loc);
+  tree val = (trait_expr_value (kind, type1, type2)
+	      ? boolean_true_node : boolean_false_node);
+  return maybe_wrap_with_location (val, loc);
 }
 
 /* Do-nothing variants of functions to handle pragma FLOAT_CONST_DECIMAL64,
--- gcc/cp/cp-gimplify.c.jj	2021-07-28 12:06:00.482928952 +0200
+++ gcc/cp/cp-gimplify.c	2021-07-28 14:49:06.034027853 +0200
@@ -648,14 +648,23 @@ cp_gimplify_expr (tree *expr_p, gimple_s
       if (ret != GS_ERROR)
 	{
 	  tree decl = cp_get_callee_fndecl_nofold (*expr_p);
-	  if (decl
-	      && fndecl_built_in_p (decl, CP_BUILT_IN_IS_CONSTANT_EVALUATED,
-				    BUILT_IN_FRONTEND))
-	    *expr_p = boolean_false_node;
-	  else if (decl
-		   && fndecl_built_in_p (decl, CP_BUILT_IN_SOURCE_LOCATION,
-					 BUILT_IN_FRONTEND))
-	    *expr_p = fold_builtin_source_location (EXPR_LOCATION (*expr_p));
+	  if (decl && fndecl_built_in_p (decl, BUILT_IN_FRONTEND))
+	    switch (DECL_FE_FUNCTION_CODE (decl))
+	      {
+	      case CP_BUILT_IN_IS_CONSTANT_EVALUATED:
+		*expr_p = boolean_false_node;
+		break;
+	      case CP_BUILT_IN_SOURCE_LOCATION:
+		*expr_p
+		  = fold_builtin_source_location (EXPR_LOCATION (*expr_p));
+		break;
+	      case CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS:
+		*expr_p
+		  = fold_builtin_is_pointer_inverconvertible_with_class
+			(EXPR_LOCATION (*expr_p), call_expr_nargs (*expr_p),
+			 &CALL_EXPR_ARG (*expr_p, 0));
+		break;
+	      }
 	}
       break;
 
@@ -2560,11 +2569,26 @@ cp_fold (tree x)
 	    && DECL_DECLARED_CONSTEXPR_P (current_function_decl))
 	  nw = 1;
 
-	/* Defer folding __builtin_is_constant_evaluated.  */
-	if (callee
-	    && fndecl_built_in_p (callee, CP_BUILT_IN_IS_CONSTANT_EVALUATED,
-				  BUILT_IN_FRONTEND))
-	  break;
+	if (callee && fndecl_built_in_p (callee, BUILT_IN_FRONTEND))
+	  {
+	    switch (DECL_FE_FUNCTION_CODE (callee))
+	      {
+		/* Defer folding __builtin_is_constant_evaluated.  */
+	      case CP_BUILT_IN_IS_CONSTANT_EVALUATED:
+		break;
+	      case CP_BUILT_IN_SOURCE_LOCATION:
+		x = fold_builtin_source_location (EXPR_LOCATION (x));
+		break;
+	      case CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS:
+                x = fold_builtin_is_pointer_inverconvertible_with_class
+			(EXPR_LOCATION (x), call_expr_nargs (x),
+			 &CALL_EXPR_ARG (x, 0));
+		break;
+	      default:
+		break;
+	      }
+	    break;
+	  }
 
 	if (callee
 	    && fndecl_built_in_p (callee, CP_BUILT_IN_SOURCE_LOCATION,
--- gcc/cp/tree.c.jj	2021-07-21 18:55:05.416625466 +0200
+++ gcc/cp/tree.c	2021-07-28 14:07:41.181568566 +0200
@@ -450,11 +450,16 @@ builtin_valid_in_constant_expr_p (const_
     return false;
   if (DECL_BUILT_IN_CLASS (decl) != BUILT_IN_NORMAL)
     {
-      if (fndecl_built_in_p (decl, CP_BUILT_IN_IS_CONSTANT_EVALUATED,
-			     BUILT_IN_FRONTEND)
-	  || fndecl_built_in_p (decl, CP_BUILT_IN_SOURCE_LOCATION,
-				BUILT_IN_FRONTEND))
-	return true;
+      if (fndecl_built_in_p (decl, BUILT_IN_FRONTEND))
+	switch (DECL_FE_FUNCTION_CODE (decl))
+	  {
+	  case CP_BUILT_IN_IS_CONSTANT_EVALUATED:
+	  case CP_BUILT_IN_SOURCE_LOCATION:
+	  case CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS:
+	    return true;
+	  default:
+	    break;
+	  }
       /* Not a built-in.  */
       return false;
     }
--- gcc/cp/cxx-pretty-print.c.jj	2021-07-21 18:55:05.344626471 +0200
+++ gcc/cp/cxx-pretty-print.c	2021-07-28 12:14:20.675189115 +0200
@@ -2645,6 +2645,9 @@ pp_cxx_trait_expression (cxx_pretty_prin
     case CPTK_IS_FINAL:
       pp_cxx_ws_string (pp, "__is_final");
       break;
+    case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
+      pp_cxx_ws_string (pp, "__is_pointer_interconvertible_base_of");
+      break;
     case CPTK_IS_POD:
       pp_cxx_ws_string (pp, "__is_pod");
       break;
@@ -2695,7 +2698,9 @@ pp_cxx_trait_expression (cxx_pretty_prin
   pp_cxx_left_paren (pp);
   pp->type_id (TRAIT_EXPR_TYPE1 (t));
 
-  if (kind == CPTK_IS_BASE_OF || kind == CPTK_IS_SAME_AS)
+  if (kind == CPTK_IS_BASE_OF
+      || kind == CPTK_IS_SAME_AS
+      || kind == CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF)
     {
       pp_cxx_separate_with (pp, ',');
       pp->type_id (TRAIT_EXPR_TYPE2 (t));
--- gcc/testsuite/g++.dg/cpp2a/is-pointer-interconvertible-base-of1.C.jj	2021-07-28 13:21:41.654721641 +0200
+++ gcc/testsuite/g++.dg/cpp2a/is-pointer-interconvertible-base-of1.C	2021-07-28 13:21:20.562005151 +0200
@@ -0,0 +1,55 @@
+// P0466R5
+// { dg-do compile { target c++20 } }
+
+namespace std
+{
+template <typename T, T v>
+struct integral_constant
+{
+  static constexpr T value = v;
+};
+
+template <typename, typename>
+struct is_pointer_interconvertible_base_of;
+
+template<typename T, typename U>
+struct is_pointer_interconvertible_base_of
+  : public integral_constant <bool, __is_pointer_interconvertible_base_of (T, U)>
+{
+};
+
+template <typename T, typename U>
+inline constexpr bool is_pointer_interconvertible_base_of_v = __is_pointer_interconvertible_base_of (T, U);
+}
+
+struct A;
+struct B { int b; };
+struct C : virtual B { int c; };
+struct D {};
+struct E {};
+struct F : public B, D, E {};
+struct G : public D, E { int g; };
+struct H {};
+struct I : public G, H {};
+struct J { int j1; private: int j2; };
+struct K : public J {};
+union U { int a; };
+
+static_assert (std::is_pointer_interconvertible_base_of<A, A>::value);
+static_assert (std::is_pointer_interconvertible_base_of_v<A, A>);
+static_assert (std::is_pointer_interconvertible_base_of_v<const A, volatile A>);
+static_assert (std::is_pointer_interconvertible_base_of_v<B, const B>);
+static_assert (std::is_pointer_interconvertible_base_of_v<C, const volatile C>);
+static_assert (!std::is_pointer_interconvertible_base_of_v<D, E>);
+static_assert (!std::is_pointer_interconvertible_base_of_v<D, const B>);
+static_assert (std::is_pointer_interconvertible_base_of_v<const B, F>);
+static_assert (std::is_pointer_interconvertible_base_of_v<D, const F>);
+static_assert (std::is_pointer_interconvertible_base_of_v<E, F>);
+static_assert (!std::is_pointer_interconvertible_base_of_v<D, volatile G>);
+static_assert (!std::is_pointer_interconvertible_base_of_v<const E, volatile G>);
+static_assert (!std::is_pointer_interconvertible_base_of_v<D, I>);
+static_assert (!std::is_pointer_interconvertible_base_of_v<const E, const I>);
+static_assert (std::is_pointer_interconvertible_base_of_v<G, I>);
+static_assert (std::is_pointer_interconvertible_base_of_v<H, volatile I>);
+static_assert (!std::is_pointer_interconvertible_base_of_v<volatile J, const K>);
+static_assert (!std::is_pointer_interconvertible_base_of_v<U, U>);
--- gcc/testsuite/g++.dg/cpp2a/is-pointer-interconvertible-with-class1.C.jj	2021-07-28 17:23:23.353247589 +0200
+++ gcc/testsuite/g++.dg/cpp2a/is-pointer-interconvertible-with-class1.C	2021-07-28 17:36:10.514918765 +0200
@@ -0,0 +1,62 @@
+// P0466R5
+// { dg-do compile { target c++20 } }
+
+namespace std
+{
+template <class S, class M>
+constexpr bool
+is_pointer_interconvertible_with_class (M S::*m) noexcept
+{
+  return __builtin_is_pointer_interconvertible_with_class (m);
+}
+}
+
+struct A;
+struct B { int b; double b2; };
+struct C : virtual B { int c; };
+struct D {};
+struct E {};
+struct F : public B, D, E {};
+struct G : public D, E { int g; };
+struct H {};
+struct I : public G, H {};
+struct J { int j1; private: int j2; public: int j3; };
+struct K : public J {};
+struct L : public B, D, E {};
+struct M { D d [[no_unique_address]]; E e [[no_unique_address]]; int f; };
+union U { int a; double b; long long c; };
+struct V { union { int a; long b; }; int c; };
+union X { int a; union { short b; long c; }; long long d; };
+struct Y { void foo () {} };
+
+static_assert (std::is_pointer_interconvertible_with_class (&B::b));
+static_assert (!std::is_pointer_interconvertible_with_class (&B::b2));
+static_assert (std::is_pointer_interconvertible_with_class (&C::b));
+static_assert (std::is_pointer_interconvertible_with_class (&F::b));
+static_assert (std::is_pointer_interconvertible_with_class<F, int> (&F::b));
+static_assert (std::is_pointer_interconvertible_with_class (&G::g));
+static_assert (std::is_pointer_interconvertible_with_class<G, int> (&G::g));
+static_assert (std::is_pointer_interconvertible_with_class (&I::g));
+static_assert (std::is_pointer_interconvertible_with_class<I, int> (&I::g));
+static_assert (!std::is_pointer_interconvertible_with_class (&J::j1));
+static_assert (!std::is_pointer_interconvertible_with_class (&J::j3));
+static_assert (!std::is_pointer_interconvertible_with_class (&K::j1));
+static_assert (!std::is_pointer_interconvertible_with_class (&K::j3));
+static_assert (std::is_pointer_interconvertible_with_class (&L::b));
+static_assert (std::is_pointer_interconvertible_with_class<L, int> (&L::b));
+static_assert (std::is_pointer_interconvertible_with_class (&L::b));
+static_assert (std::is_pointer_interconvertible_with_class (&M::d));
+static_assert (!std::is_pointer_interconvertible_with_class (&M::e));
+static_assert (!std::is_pointer_interconvertible_with_class (&M::f));
+static_assert (std::is_pointer_interconvertible_with_class (&U::a));
+static_assert (std::is_pointer_interconvertible_with_class (&U::b));
+static_assert (std::is_pointer_interconvertible_with_class (&U::c));
+static_assert (std::is_pointer_interconvertible_with_class (&V::a));
+static_assert (std::is_pointer_interconvertible_with_class (&V::b));
+static_assert (!std::is_pointer_interconvertible_with_class (&V::c));
+static_assert (std::is_pointer_interconvertible_with_class (&X::a));
+static_assert (std::is_pointer_interconvertible_with_class (&X::b));
+static_assert (std::is_pointer_interconvertible_with_class (&X::c));
+static_assert (std::is_pointer_interconvertible_with_class (&X::d));
+static_assert (!std::is_pointer_interconvertible_with_class ((int B::*) nullptr));
+static_assert (!std::is_pointer_interconvertible_with_class (&Y::foo));
--- gcc/testsuite/g++.dg/cpp2a/is-pointer-interconvertible-with-class2.C.jj	2021-07-28 17:31:11.981938196 +0200
+++ gcc/testsuite/g++.dg/cpp2a/is-pointer-interconvertible-with-class2.C	2021-07-28 17:39:45.458022541 +0200
@@ -0,0 +1,128 @@
+// P0466R5
+// { dg-do run { target c++20 } }
+
+namespace std
+{
+template <class S, class M>
+constexpr bool
+is_pointer_interconvertible_with_class (M S::*m) noexcept
+{
+  return __builtin_is_pointer_interconvertible_with_class (m);
+}
+}
+
+struct A;
+struct B { int b; double b2; };
+struct C : virtual B { int c; };
+struct D {};
+struct E {};
+struct F : public B, D, E {};
+struct G : public D, E { int g; };
+struct H {};
+struct I : public G, H {};
+struct J { int j1; private: int j2; public: int j3; };
+struct K : public J {};
+struct L : public B, D, E {};
+struct M { D d [[no_unique_address]]; E e [[no_unique_address]]; int f; };
+union U { int a; double b; long long c; };
+struct V { union { int a; long b; }; int c; };
+union X { int a; union { short b; long c; }; long long d; };
+struct Y { void foo () {} };
+
+int
+main ()
+{
+  auto t1 = &B::b;
+  if (!std::is_pointer_interconvertible_with_class (t1))
+    __builtin_abort ();
+  auto t2 = &B::b2;
+  if (std::is_pointer_interconvertible_with_class (t2))
+    __builtin_abort ();
+  auto t3 = &C::b;
+  if (!std::is_pointer_interconvertible_with_class (t3))
+    __builtin_abort ();
+  auto t4 = &F::b;
+  if (!std::is_pointer_interconvertible_with_class (t4))
+    __builtin_abort ();
+  int F::*t5 = &F::b;
+  if (!std::is_pointer_interconvertible_with_class (t5))
+    __builtin_abort ();
+  auto t6 = &G::g;
+  if (!std::is_pointer_interconvertible_with_class (t6))
+    __builtin_abort ();
+  int G::*t7 = &G::g;
+  if (!std::is_pointer_interconvertible_with_class (t7))
+    __builtin_abort ();
+  auto t8 = &I::g;
+  if (!std::is_pointer_interconvertible_with_class (t8))
+    __builtin_abort ();
+  int I::*t9 = &I::g;
+  if (!std::is_pointer_interconvertible_with_class (t9))
+    __builtin_abort ();
+  auto t10 = &J::j1;
+  if (std::is_pointer_interconvertible_with_class (t10))
+    __builtin_abort ();
+  auto t11 = &J::j3;
+  if (std::is_pointer_interconvertible_with_class (t11))
+    __builtin_abort ();
+  auto t12 = &K::j1;
+  if (std::is_pointer_interconvertible_with_class (t12))
+    __builtin_abort ();
+  auto t13 = &K::j3;
+  if (std::is_pointer_interconvertible_with_class (t13))
+    __builtin_abort ();
+  auto t14 = &L::b;
+  if (!std::is_pointer_interconvertible_with_class (t14))
+    __builtin_abort ();
+  int L::*t15 = &L::b;
+  if (!std::is_pointer_interconvertible_with_class (t15))
+    __builtin_abort ();
+  auto t16 = &L::b;
+  if (!std::is_pointer_interconvertible_with_class (t16))
+    __builtin_abort ();
+  auto t17 = &M::d;
+  if (!std::is_pointer_interconvertible_with_class (t17))
+    __builtin_abort ();
+  auto t18 = &M::e;
+  if (std::is_pointer_interconvertible_with_class (t18))
+    __builtin_abort ();
+  auto t19 = &M::f;
+  if (std::is_pointer_interconvertible_with_class (t19))
+    __builtin_abort ();
+  auto t20 = &U::a;
+  if (!std::is_pointer_interconvertible_with_class (t20))
+    __builtin_abort ();
+  auto t21 = &U::b;
+  if (!std::is_pointer_interconvertible_with_class (t21))
+    __builtin_abort ();
+  auto t22 = &U::c;
+  if (!std::is_pointer_interconvertible_with_class (t22))
+    __builtin_abort ();
+  auto t23 = &V::a;
+  if (!std::is_pointer_interconvertible_with_class (t23))
+    __builtin_abort ();
+  auto t24 = &V::b;
+  if (!std::is_pointer_interconvertible_with_class (t24))
+    __builtin_abort ();
+  auto t25 = &V::c;
+  if (std::is_pointer_interconvertible_with_class (t25))
+    __builtin_abort ();
+  auto t26 = &X::a;
+  if (!std::is_pointer_interconvertible_with_class (t26))
+    __builtin_abort ();
+  auto t27 = &X::b;
+  if (!std::is_pointer_interconvertible_with_class (t27))
+    __builtin_abort ();
+  auto t28 = &X::c;
+  if (!std::is_pointer_interconvertible_with_class (t28))
+    __builtin_abort ();
+  auto t29 = &X::d;
+  if (!std::is_pointer_interconvertible_with_class (t29))
+    __builtin_abort ();
+  auto t30 = (int B::*) nullptr;
+  if (std::is_pointer_interconvertible_with_class (t30))
+    __builtin_abort ();
+  auto t31 = &Y::foo;
+  if (std::is_pointer_interconvertible_with_class (t31))
+    __builtin_abort ();
+}
--- gcc/testsuite/g++.dg/cpp2a/is-pointer-interconvertible-with-class3.C.jj	2021-07-28 17:31:19.863832080 +0200
+++ gcc/testsuite/g++.dg/cpp2a/is-pointer-interconvertible-with-class3.C	2021-07-28 17:34:52.767965633 +0200
@@ -0,0 +1,11 @@
+// P0466R5
+// { dg-do compile { target c++20 } }
+
+struct A { int a; };
+struct B;
+
+bool a = __builtin_is_pointer_interconvertible_with_class ();			// { dg-error "needs a single argument" }
+bool b = __builtin_is_pointer_interconvertible_with_class (&A::a, &A::a);	// { dg-error "needs a single argument" }
+bool c = __builtin_is_pointer_interconvertible_with_class (1);			// { dg-error "argument is not pointer to member" }
+bool d = __builtin_is_pointer_interconvertible_with_class (1.0);		// { dg-error "argument is not pointer to member" }
+bool e = __builtin_is_pointer_interconvertible_with_class ((int B::*) nullptr);	// { dg-error "invalid use of incomplete type" }
--- gcc/testsuite/g++.dg/cpp2a/is-pointer-interconvertible-with-class4.C.jj	2021-07-28 17:36:30.412650659 +0200
+++ gcc/testsuite/g++.dg/cpp2a/is-pointer-interconvertible-with-class4.C	2021-07-28 17:37:30.435841885 +0200
@@ -0,0 +1,24 @@
+// P0466R5
+// { dg-do compile { target c++20 } }
+// { dg-options "" }
+
+namespace std
+{
+template <class S, class M>
+constexpr bool
+is_pointer_interconvertible_with_class (M S::*m) noexcept
+{
+  return __builtin_is_pointer_interconvertible_with_class (m);
+}
+}
+
+struct W { struct { int a; long b; }; int c; };
+union X { int a; struct { short b; long c; }; long long d; };
+
+static_assert (std::is_pointer_interconvertible_with_class (&W::a));
+static_assert (!std::is_pointer_interconvertible_with_class (&W::b));
+static_assert (!std::is_pointer_interconvertible_with_class (&W::c));
+static_assert (std::is_pointer_interconvertible_with_class (&X::a));
+static_assert (std::is_pointer_interconvertible_with_class (&X::b));
+static_assert (!std::is_pointer_interconvertible_with_class (&X::c));
+static_assert (std::is_pointer_interconvertible_with_class (&X::d));
--- gcc/testsuite/g++.dg/cpp2a/is-pointer-interconvertible-with-class5.C.jj	2021-07-28 17:36:35.294584876 +0200
+++ gcc/testsuite/g++.dg/cpp2a/is-pointer-interconvertible-with-class5.C	2021-07-28 17:39:08.795516549 +0200
@@ -0,0 +1,42 @@
+// P0466R5
+// { dg-do run { target c++20 } }
+// { dg-options "" }
+
+namespace std
+{
+template <class S, class M>
+constexpr bool
+is_pointer_interconvertible_with_class (M S::*m) noexcept
+{
+  return __builtin_is_pointer_interconvertible_with_class (m);
+}
+}
+
+struct W { struct { int a; long b; }; int c; };
+union X { int a; struct { short b; long c; }; long long d; };
+
+int
+main ()
+{
+  auto t1 = &W::a;
+  if (!std::is_pointer_interconvertible_with_class (t1))
+    __builtin_abort ();
+  auto t2 = &W::b;
+  if (std::is_pointer_interconvertible_with_class (t2))
+    __builtin_abort ();
+  auto t3 = &W::c;
+  if (std::is_pointer_interconvertible_with_class (t3))
+    __builtin_abort ();
+  auto t4 = &X::a;
+  if (!std::is_pointer_interconvertible_with_class (t4))
+    __builtin_abort ();
+  auto t5 = &X::b;
+  if (!std::is_pointer_interconvertible_with_class (t5))
+    __builtin_abort ();
+  auto t6 = &X::c;
+  if (std::is_pointer_interconvertible_with_class (t6))
+    __builtin_abort ();
+  auto t7 = &X::d;
+  if (!std::is_pointer_interconvertible_with_class (t7))
+    __builtin_abort ();
+}
--- gcc/testsuite/g++.dg/cpp2a/is-pointer-interconvertible-with-class6.C.jj	2021-05-25 17:45:05.138850892 +0200
+++ gcc/testsuite/g++.dg/cpp2a/is-pointer-interconvertible-with-class6.C	2021-07-28 17:53:43.244733852 +0200
@@ -0,0 +1,19 @@
+// P0466R5
+// { dg-do compile { target c++20 } }
+
+namespace std
+{
+template <class S, class M>
+constexpr bool
+is_pointer_interconvertible_with_class (M S::*m) noexcept
+{
+  return __builtin_is_pointer_interconvertible_with_class (m);
+}
+}
+
+struct A { int a; };
+
+double A::*a = nullptr;
+constexpr double A::*b = nullptr;
+constexpr auto c = std::is_pointer_interconvertible_with_class (a);	// { dg-error "is not usable in a constant expression" }
+constexpr auto d = std::is_pointer_interconvertible_with_class (b);
