]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: Add missing explanations for is_constructible<Abstract>
authorNathaniel Shead <nathanieloshead@gmail.com>
Thu, 11 Dec 2025 21:57:20 +0000 (08:57 +1100)
committerNathaniel Shead <nathanieloshead@gmail.com>
Fri, 12 Dec 2025 23:36:44 +0000 (10:36 +1100)
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 <nathanieloshead@gmail.com>
Reviewed-by: Jason Merrill <jason@redhat.com>
gcc/cp/method.cc
gcc/cp/typeck2.cc
gcc/testsuite/g++.dg/ext/is_constructible9.C

index 39f931eafc9d58cc0657cb2bf30eb947ab7fd85f..170f986d6e859b28d739a88cae1f05612e41cf29 100644 (file)
@@ -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;
index d77de9212ed3e1c022b2df6527d36dbf1c85d9c6..3da74e8b0680c7b7eba92f729c0d05ecf3b74905 100644 (file)
@@ -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
index 5448878c122f3b117bf380144d96925c6f7cd511..d9e7b0e46a65f583fc327a67558ed7eb30c324a8 100644 (file)
@@ -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...);