On 12/12/25 6:07 AM, Nathaniel Shead wrote:
Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?

OK.

-- >8 --

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]>
---
  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 39f931eafc9..170f986d6e8 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 d77de9212ed..3da74e8b068 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 5448878c122..d9e7b0e46a6 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...);

Reply via email to