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);
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);
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,
--- /dev/null
+// { 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 }