]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: Add detailed diagnostics for __is_pointer_interconvertible_base_of
authorNathaniel Shead <nathanieloshead@gmail.com>
Sat, 25 Oct 2025 11:40:06 +0000 (22:40 +1100)
committerNathaniel Shead <nathanieloshead@gmail.com>
Sat, 22 Nov 2025 23:45:13 +0000 (10:45 +1100)
gcc/cp/ChangeLog:

* constraint.cc (diagnose_trait_expr):
<case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF>: Explain failure
with more detail.
* cp-tree.h (pointer_interconvertible_base_of_p): Add explain
parameter.
* semantics.cc (pointer_interconvertible_base_of_p): Explain why
not.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/is-pointer-interconvertible-base-of2.C: New test.

Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
Reviewed-by: Jason Merrill <jason@redhat.com>
gcc/cp/constraint.cc
gcc/cp/cp-tree.h
gcc/cp/semantics.cc
gcc/testsuite/g++.dg/cpp2a/is-pointer-interconvertible-base-of2.C [new file with mode: 0644]

index 19d2d8f82d512d82ca8beefcc73ebf5dcd662f9c..6abd0966fcd1d7761649d6137dcc0eb836b9807c 100644 (file)
@@ -3239,8 +3239,9 @@ diagnose_trait_expr (location_t loc, tree expr, tree args)
       break;
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       inform (location_of (t2),
-             "%qT is not a pointer-interconvertible base of %qT",
+             "%qT is not a pointer-interconvertible base of %qT, because",
              t1, t2);
+      pointer_interconvertible_base_of_p (t1, t2, /*explain=*/true);
       break;
     case CPTK_IS_POD:
       inform (loc, "%qT is not a POD type", t1);
index 5244370f7c6ccf6ac4ef649203dbeebbf0493929..4efddd98537d8e3fc4e345f51a9513abf5ed38c5 100644 (file)
@@ -8291,6 +8291,7 @@ extern void finish_static_assert                (tree, tree, location_t,
                                                 bool, bool, bool = false);
 extern tree finish_decltype_type                (tree, bool, tsubst_flags_t);
 extern tree fold_builtin_is_corresponding_member (location_t, int, tree *);
+extern bool pointer_interconvertible_base_of_p (tree, tree, bool = false);
 extern tree fold_builtin_is_pointer_inverconvertible_with_class (location_t, int, tree *);
 extern tree finish_structured_binding_size     (location_t, tree, tsubst_flags_t);
 extern tree finish_trait_expr                  (location_t, enum cp_trait_kind, tree, tree);
index 0d8981ecabf9a446f82ad2bb967ec99b25c99bc4..f472be21c4bbdb89841cd5c06b98f408cb6bfdf7 100644 (file)
@@ -13088,26 +13088,57 @@ classtype_has_nothrow_assign_or_copy_p (tree type, bool assign_p)
   return saw_copy;
 }
 
-/* Return true if DERIVED is pointer interconvertible base of BASE.  */
+/* Return true if BASE is a pointer-interconvertible base of DERIVED.  */
 
-static bool
-pointer_interconvertible_base_of_p (tree base, tree derived)
+bool
+pointer_interconvertible_base_of_p (tree base, tree derived,
+                                   bool explain/*=false*/)
 {
   if (base == error_mark_node || derived == error_mark_node)
     return false;
+
   base = TYPE_MAIN_VARIANT (base);
   derived = TYPE_MAIN_VARIANT (derived);
-  if (!NON_UNION_CLASS_TYPE_P (base)
-      || !NON_UNION_CLASS_TYPE_P (derived))
-    return false;
+  if (!NON_UNION_CLASS_TYPE_P (base))
+    {
+      if (explain)
+       inform (location_of (base),
+               "%qT is not a non-union class type", base);
+      return false;
+    }
+  if (!NON_UNION_CLASS_TYPE_P (derived))
+    {
+      if (explain)
+       inform (location_of (derived),
+               "%qT is not a non-union class type", derived);
+      return false;
+    }
 
   if (same_type_p (base, derived))
     return true;
 
   if (!std_layout_type_p (derived))
-    return false;
+    {
+      if (explain)
+       inform (location_of (derived),
+               "%qT is not a standard-layout type", derived);
+      return false;
+    }
+
+  if (!uniquely_derived_from_p (base, derived))
+    {
+      if (explain)
+       {
+         /* An ambiguous base should already be impossible due to
+            the std_layout_type_p check.  */
+         gcc_checking_assert (!DERIVED_FROM_P (base, derived));
+         inform (location_of (derived),
+                 "%qT is not a base of %qT", base, derived);
+       }
+      return false;
+    }
 
-  return uniquely_derived_from_p (base, derived);
+  return true;
 }
 
 /* Helper function for fold_builtin_is_pointer_inverconvertible_with_class,
diff --git a/gcc/testsuite/g++.dg/cpp2a/is-pointer-interconvertible-base-of2.C b/gcc/testsuite/g++.dg/cpp2a/is-pointer-interconvertible-base-of2.C
new file mode 100644 (file)
index 0000000..9530f9e
--- /dev/null
@@ -0,0 +1,29 @@
+// { dg-do compile { target c++20 } }
+// { dg-additional-options "-Wno-inaccessible-base" }
+
+template <typename T, typename U>
+constexpr bool pointer_interconvertible_base_of
+  = __is_pointer_interconvertible_base_of(T, U);
+
+struct A {};
+struct B {};  // { dg-message "not a pointer-interconvertible base" }
+static_assert(pointer_interconvertible_base_of<A, B>);  // { dg-error "assert" }
+
+struct C {
+  int x;
+private:
+  int y;
+};
+struct D : C {};  // { dg-message "standard-layout" }
+static_assert(pointer_interconvertible_base_of<C, D>);  // { dg-error "assert" }
+
+struct E {};
+struct F : E {};
+struct G : F, E {};  // { dg-message "standard-layout" }
+static_assert(pointer_interconvertible_base_of<E, G>);  // { dg-error "assert" }
+
+union H {};  // { dg-message "non-union" }
+static_assert(pointer_interconvertible_base_of<H, H>);  // { dg-error "assert" }
+
+static_assert(pointer_interconvertible_base_of<A, int>);  // { dg-error "assert" }
+// { dg-message "non-union" "" { target *-*-* } .-1 }