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