https://gcc.gnu.org/g:3cb51cda4c23002a1bad8eac64b4f76ce51ad1b3
commit r16-6075-g3cb51cda4c23002a1bad8eac64b4f76ce51ad1b3 Author: Nathaniel Shead <[email protected]> Date: Fri Dec 12 08:57:20 2025 +1100 c++: Add missing explanations for is_constructible<Abstract> Checking whether an abstract class type is constructible currently is missing an explanation. With this patch, we now get the following output for an abstract type: test.cpp:7:20: error: static assertion failed 7 | static_assert(std::is_default_constructible_v<A>); | ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ • ‘A’ is not default constructible, because • error: cannot construct an object of abstract type ‘A’ • because the following virtual functions are pure within ‘A’: test.cpp:3:8: 3 | struct A { | ^ • ‘virtual void A::foo()’ test.cpp:4:18: 4 | virtual void foo() = 0; | ^~~ Before this patch, the diagnostic stopped after the "A is not default constructible, because" message. gcc/cp/ChangeLog: * method.cc (constructible_expr): Emit diagnostics for abstract types. * typeck2.cc (abstract_virtuals_error): Use more accurate wording for default case, and remove extranneous whitespace in favour of a nesting level. gcc/testsuite/ChangeLog: * g++.dg/ext/is_constructible9.C: Add to testcase. Signed-off-by: Nathaniel Shead <[email protected]> Reviewed-by: Jason Merrill <[email protected]> Diff: --- gcc/cp/method.cc | 2 +- gcc/cp/typeck2.cc | 7 ++++--- gcc/testsuite/g++.dg/ext/is_constructible9.C | 6 ++++++ 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc index 39f931eafc9d..170f986d6e85 100644 --- a/gcc/cp/method.cc +++ b/gcc/cp/method.cc @@ -2274,7 +2274,7 @@ constructible_expr (tree to, tree from, bool explain) const int len = TREE_VEC_LENGTH (from); if (CLASS_TYPE_P (to)) { - if (ABSTRACT_CLASS_TYPE_P (to)) + if (abstract_virtuals_error (NULL_TREE, to, complain)) return error_mark_node; tree ctype = to; vec<tree, va_gc> *args = NULL; diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc index d77de9212ed3..3da74e8b0680 100644 --- a/gcc/cp/typeck2.cc +++ b/gcc/cp/typeck2.cc @@ -228,7 +228,7 @@ abstract_virtuals_error (tree decl, tree type, abstract_class_use use, "class type %qT", type); break; default: - error ("cannot allocate an object of abstract type %qT", type); + error ("cannot construct an object of abstract type %qT", type); } /* Only go through this once. */ @@ -238,13 +238,14 @@ abstract_virtuals_error (tree decl, tree type, abstract_class_use use, tree fn; inform (DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (type)), - " because the following virtual functions are pure within %qT:", + "because the following virtual functions are pure within %qT:", type); + auto_diagnostic_nesting_level adnl; FOR_EACH_VEC_ELT (*pure, ix, fn) if (! DECL_CLONED_FUNCTION_P (fn) || DECL_COMPLETE_DESTRUCTOR_P (fn)) - inform (DECL_SOURCE_LOCATION (fn), " %#qD", fn); + inform (DECL_SOURCE_LOCATION (fn), "%#qD", fn); /* Now truncate the vector. This leaves it non-null, so we know there are pure virtuals, but empty so we don't list them out diff --git a/gcc/testsuite/g++.dg/ext/is_constructible9.C b/gcc/testsuite/g++.dg/ext/is_constructible9.C index 5448878c122f..d9e7b0e46a65 100644 --- a/gcc/testsuite/g++.dg/ext/is_constructible9.C +++ b/gcc/testsuite/g++.dg/ext/is_constructible9.C @@ -24,6 +24,12 @@ static_assert(is_constructible<A, int, int>::value, ""); // { dg-error "assert" // { dg-message "'A' is not constructible from 'int, int', because" "" { target *-*-* } .-1 } // { dg-error "no matching function for call to" "" { target *-*-* } .-2 } +struct V { // { dg-message "following virtual functions are pure" } + virtual void foo() = 0; // { dg-message "" } +}; +static_assert(is_constructible<V>::value, ""); // { dg-error "assert" } +// { dg-error "object of abstract type" "" { target *-*-* } .-1 } + template <typename T, typename... Args> struct is_nothrow_constructible { static constexpr bool value = __is_nothrow_constructible(T, Args...);
