Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?

-- >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...);
-- 
2.51.0

Reply via email to