c++: hard error w/ ptr+CST and incomplete type [PR103700]

Message ID 20211222173904.3231408-1-ppalka@redhat.com
State New
Headers
Series c++: hard error w/ ptr+CST and incomplete type [PR103700] |

Commit Message

Patrick Palka Dec. 22, 2021, 5:39 p.m. UTC
  In pointer_int_sum when called from a SFINAE context, we need to avoid
calling size_in_bytes_loc on an incomplete pointed-to type since this
latter function isn't SFINAE-friendly and always emits an error in this
case.

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk and perhaps 11?  pointer_int_sum is also used in the C FE, but
always with the complain parameter defaulted to true so this change
should have no effect there AFAICT.

	PR c++/103700

gcc/c-family/ChangeLog:

	* c-common.c (pointer_int_sum): When quiet, return
	error_mark_node for an incomplete type and avoid calling
	size_in_bytes_loc.

gcc/testsuite/ChangeLog:

	* g++.dg/template/sfinae32.C: New test.
---
 gcc/c-family/c-common.c                  |  2 ++
 gcc/testsuite/g++.dg/template/sfinae32.C | 17 +++++++++++++++++
 2 files changed, 19 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/template/sfinae32.C
  

Comments

Jason Merrill Dec. 22, 2021, 5:44 p.m. UTC | #1
On 12/22/21 12:39, Patrick Palka wrote:
> In pointer_int_sum when called from a SFINAE context, we need to avoid
> calling size_in_bytes_loc on an incomplete pointed-to type since this
> latter function isn't SFINAE-friendly and always emits an error in this
> case.
> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk and perhaps 11?  pointer_int_sum is also used in the C FE, but
> always with the complain parameter defaulted to true so this change
> should have no effect there AFAICT.

LGTM, but let's give the C maintainers time to comment; OK on Friday if 
no comment.

> 	PR c++/103700
> 
> gcc/c-family/ChangeLog:
> 
> 	* c-common.c (pointer_int_sum): When quiet, return
> 	error_mark_node for an incomplete type and avoid calling
> 	size_in_bytes_loc.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/template/sfinae32.C: New test.
> ---
>   gcc/c-family/c-common.c                  |  2 ++
>   gcc/testsuite/g++.dg/template/sfinae32.C | 17 +++++++++++++++++
>   2 files changed, 19 insertions(+)
>   create mode 100644 gcc/testsuite/g++.dg/template/sfinae32.C
> 
> diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
> index a25d59fa77b..f3e3e9ba0a5 100644
> --- a/gcc/c-family/c-common.c
> +++ b/gcc/c-family/c-common.c
> @@ -3308,6 +3308,8 @@ pointer_int_sum (location_t loc, enum tree_code resultcode,
>       size_exp = integer_one_node;
>     else
>       {
> +      if (!complain && !COMPLETE_TYPE_P (TREE_TYPE (result_type)))
> +	return error_mark_node;
>         size_exp = size_in_bytes_loc (loc, TREE_TYPE (result_type));
>         /* Wrap the pointer expression in a SAVE_EXPR to make sure it
>   	 is evaluated first when the size expression may depend
> diff --git a/gcc/testsuite/g++.dg/template/sfinae32.C b/gcc/testsuite/g++.dg/template/sfinae32.C
> new file mode 100644
> index 00000000000..488bf145e21
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/template/sfinae32.C
> @@ -0,0 +1,17 @@
> +// PR c++/103700
> +// { dg-do compile { target c++11 } }
> +
> +template<class T, T **p, int N> auto f() -> decltype(*p + N) = delete;
> +template<class T, T **p, int N> auto f() -> decltype(*p - N) = delete;
> +template<class T, T **p, int N> auto f() -> decltype(N + *p) = delete;
> +template<class T, T **p, int N> void f();
> +
> +struct Incomplete *p;
> +
> +int main() {
> +  f<Incomplete, &p, 0>();
> +  f<Incomplete, &p, 1>();
> +  f<Incomplete, &p, -1>();
> +  f<Incomplete, &p, 42>();
> +  f<Incomplete, &p, -42>();
> +}
  

Patch

diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index a25d59fa77b..f3e3e9ba0a5 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -3308,6 +3308,8 @@  pointer_int_sum (location_t loc, enum tree_code resultcode,
     size_exp = integer_one_node;
   else
     {
+      if (!complain && !COMPLETE_TYPE_P (TREE_TYPE (result_type)))
+	return error_mark_node;
       size_exp = size_in_bytes_loc (loc, TREE_TYPE (result_type));
       /* Wrap the pointer expression in a SAVE_EXPR to make sure it
 	 is evaluated first when the size expression may depend
diff --git a/gcc/testsuite/g++.dg/template/sfinae32.C b/gcc/testsuite/g++.dg/template/sfinae32.C
new file mode 100644
index 00000000000..488bf145e21
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/sfinae32.C
@@ -0,0 +1,17 @@ 
+// PR c++/103700
+// { dg-do compile { target c++11 } }
+
+template<class T, T **p, int N> auto f() -> decltype(*p + N) = delete;
+template<class T, T **p, int N> auto f() -> decltype(*p - N) = delete;
+template<class T, T **p, int N> auto f() -> decltype(N + *p) = delete;
+template<class T, T **p, int N> void f();
+
+struct Incomplete *p;
+
+int main() {
+  f<Incomplete, &p, 0>();
+  f<Incomplete, &p, 1>();
+  f<Incomplete, &p, -1>();
+  f<Incomplete, &p, 42>();
+  f<Incomplete, &p, -42>();
+}