[C++] c++: Poor diagnostic for dynamic_cast in constexpr context [PR93414]
diff mbox series

Message ID 20200124232005.1258960-1-polacek@redhat.com
State New
Headers show
Series
  • [C++] c++: Poor diagnostic for dynamic_cast in constexpr context [PR93414]
Related show

Commit Message

Marek Polacek Jan. 24, 2020, 11:20 p.m. UTC
I neglected to add a proper diagnostic for the reference dynamic_cast
case when the operand of a dynamic_cast doesn't refer to a public base
of Derived, resulting in suboptimal error message

   error: call to non-'constexpr' function 'void* __cxa_bad_cast()'

Tested x86_64-linux, ok for trunk?

2020-01-24  Marek Polacek  <polacek@redhat.com>

	PR c++/93414 - poor diagnostic for dynamic_cast in constexpr context.
	* constexpr.c (cxx_eval_dynamic_cast_fn): Add a reference
	dynamic_cast diagnostic.
	
	* g++.dg/cpp2a/constexpr-dynamic18.C: New test.
---
 gcc/cp/constexpr.c                            | 15 ++++++++++++-
 .../g++.dg/cpp2a/constexpr-dynamic18.C        | 22 +++++++++++++++++++
 2 files changed, 36 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic18.C


base-commit: 55dd44535d2e4e5703c0103c26e7c51ab8c502c4

Comments

Jason Merrill Jan. 25, 2020, 3:39 a.m. UTC | #1
[C++ PATCH] c++: is unnecessarily redundant, you can just write [PATCH].

On 1/24/20 6:20 PM, Marek Polacek wrote:> I neglected to add a proper 
diagnostic for the reference dynamic_cast> case when the operand of a 
dynamic_cast doesn't refer to a public base> of Derived, resulting in 
suboptimal error message>
>     error: call to non-'constexpr' function 'void* __cxa_bad_cast()'
> 
> Tested x86_64-linux, ok for trunk?

OK.

> 2020-01-24  Marek Polacek  <polacek@redhat.com>
> 
> 	PR c++/93414 - poor diagnostic for dynamic_cast in constexpr context.
> 	* constexpr.c (cxx_eval_dynamic_cast_fn): Add a reference
> 	dynamic_cast diagnostic.
> 	
> 	* g++.dg/cpp2a/constexpr-dynamic18.C: New test.
> ---
>   gcc/cp/constexpr.c                            | 15 ++++++++++++-
>   .../g++.dg/cpp2a/constexpr-dynamic18.C        | 22 +++++++++++++++++++
>   2 files changed, 36 insertions(+), 1 deletion(-)
>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic18.C
> 
> diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
> index 8e8806345c1..577022e9b9a 100644
> --- a/gcc/cp/constexpr.c
> +++ b/gcc/cp/constexpr.c
> @@ -1888,7 +1888,20 @@ cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call,
>     if (tree t = (TREE_CODE (obj) == COMPONENT_REF
>   		? TREE_OPERAND (obj, 1) : obj))
>       if (TREE_CODE (t) != FIELD_DECL || !DECL_FIELD_IS_BASE (t))
> -      return integer_zero_node;
> +      {
> +	if (reference_p)
> +	  {
> +	    if (!ctx->quiet)
> +	      {
> +		error_at (loc, "reference %<dynamic_cast%> failed");
> +		inform (loc, "dynamic type %qT of its operand does "
> +			"not have a base class of type %qT",
> +			objtype, type);
> +	      }
> +	    *non_constant_p = true;
> +	  }
> +	return integer_zero_node;
> +      }
>   
>     /* [class.cdtor] When a dynamic_cast is used in a constructor ...
>        or in a destructor ... if the operand of the dynamic_cast refers
> diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic18.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic18.C
> new file mode 100644
> index 00000000000..346f9f56470
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic18.C
> @@ -0,0 +1,22 @@
> +// PR c++/93414 - poor diagnostic for dynamic_cast in constexpr context.
> +// { dg-do compile { target c++2a } }
> +// Here 'b' doesn't point/refer to a public base of Derived.
> +
> +struct Base {
> +    constexpr virtual ~Base(){}
> +};
> +
> +struct Derived: Base {
> +    constexpr ~Derived(){}
> +};
> +
> +constexpr const Derived& cast(const Base& b) {
> +    return dynamic_cast<const Derived&>(b); // { dg-error "reference .dynamic_cast. failed" }
> +// { dg-message "dynamic type .const Base. of its operand does not have a base class of type .Derived." "" { target *-*-* } .-1 }
> +}
> +
> +auto test() {
> +    static constexpr Base b;
> +    constexpr auto res = cast(b);
> +    return res;
> +}
> 
> base-commit: 55dd44535d2e4e5703c0103c26e7c51ab8c502c4
>
Marek Polacek Jan. 25, 2020, 7:09 p.m. UTC | #2
On Fri, Jan 24, 2020 at 10:39:14PM -0500, Jason Merrill wrote:
> [C++ PATCH] c++: is unnecessarily redundant, you can just write [PATCH].

True enough, I've dropped --subject-prefix from my git patch alias.

> On 1/24/20 6:20 PM, Marek Polacek wrote:> I neglected to add a proper
> diagnostic for the reference dynamic_cast> case when the operand of a
> dynamic_cast doesn't refer to a public base> of Derived, resulting in
> suboptimal error message>
> >     error: call to non-'constexpr' function 'void* __cxa_bad_cast()'
> > 
> > Tested x86_64-linux, ok for trunk?
> 
> OK.

Thanks.

Marek

Patch
diff mbox series

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 8e8806345c1..577022e9b9a 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -1888,7 +1888,20 @@  cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call,
   if (tree t = (TREE_CODE (obj) == COMPONENT_REF
 		? TREE_OPERAND (obj, 1) : obj))
     if (TREE_CODE (t) != FIELD_DECL || !DECL_FIELD_IS_BASE (t))
-      return integer_zero_node;
+      {
+	if (reference_p)
+	  {
+	    if (!ctx->quiet)
+	      {
+		error_at (loc, "reference %<dynamic_cast%> failed");
+		inform (loc, "dynamic type %qT of its operand does "
+			"not have a base class of type %qT",
+			objtype, type);
+	      }
+	    *non_constant_p = true;
+	  }
+	return integer_zero_node;
+      }
 
   /* [class.cdtor] When a dynamic_cast is used in a constructor ...
      or in a destructor ... if the operand of the dynamic_cast refers
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic18.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic18.C
new file mode 100644
index 00000000000..346f9f56470
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic18.C
@@ -0,0 +1,22 @@ 
+// PR c++/93414 - poor diagnostic for dynamic_cast in constexpr context.
+// { dg-do compile { target c++2a } }
+// Here 'b' doesn't point/refer to a public base of Derived.
+
+struct Base {
+    constexpr virtual ~Base(){}
+};
+
+struct Derived: Base {
+    constexpr ~Derived(){}
+};
+
+constexpr const Derived& cast(const Base& b) {
+    return dynamic_cast<const Derived&>(b); // { dg-error "reference .dynamic_cast. failed" }
+// { dg-message "dynamic type .const Base. of its operand does not have a base class of type .Derived." "" { target *-*-* } .-1 }
+}
+
+auto test() {
+    static constexpr Base b;
+    constexpr auto res = cast(b);
+    return res;
+}