c++: Handle SCOPE_REF in contains_placeholder_p [PR117158]

Message ID 01020192e6fb44f4-ef53170f-2e9d-427a-ad18-e4fc2dd31c25-000000@eu-west-1.amazonses.com
State New
Headers
Series c++: Handle SCOPE_REF in contains_placeholder_p [PR117158] |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_gcc_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_gcc_check--master-aarch64 success Test passed
linaro-tcwg-bot/tcwg_gcc_check--master-arm success Test passed

Commit Message

Simon Martin Nov. 1, 2024, 9:07 a.m. UTC
  Since r10-3793-g1a37b6d9a7e57c, we ICE upon the following valid code
with -std=c++17 and above

=== cut here ===
struct Base {
  unsigned int *intarray;
};
template <typename T> struct Sub : public Base {
  bool Get(int i) {
    return (Base::intarray[++i] == 0);
  }
};
=== cut here ===

The problem is that from c++17 on, we use -fstrong-eval-order and need
to wrap the array access expression into a SAVE_EXPR, and end up calling
contains_placeholder_p with a SCOPE_REF, that it does not handle well.

This patch fixes this by skipping the first operand of SCOPE_REFs in
contains_placeholder_p.

Successfully tested on x86_64-pc-linux-gnu.

	PR c++/117158

gcc/ChangeLog:

	* tree.cc (contains_placeholder_p): Skip the first operand of
	SCOPE_REFs.

gcc/testsuite/ChangeLog:

	* g++.dg/parse/crash77.C: New test.

---
 gcc/testsuite/g++.dg/parse/crash77.C | 13 +++++++++++++
 gcc/tree.cc                          |  3 +++
 2 files changed, 16 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/parse/crash77.C
  

Comments

Jason Merrill Nov. 1, 2024, 3:31 p.m. UTC | #1
On 11/1/24 5:07 AM, Simon Martin wrote:
> Since r10-3793-g1a37b6d9a7e57c, we ICE upon the following valid code
> with -std=c++17 and above
> 
> === cut here ===
> struct Base {
>    unsigned int *intarray;
> };
> template <typename T> struct Sub : public Base {
>    bool Get(int i) {
>      return (Base::intarray[++i] == 0);
>    }
> };
> === cut here ===
> 
> The problem is that from c++17 on, we use -fstrong-eval-order and need
> to wrap the array access expression into a SAVE_EXPR, and end up calling
> contains_placeholder_p with a SCOPE_REF, that it does not handle well.
> 
> This patch fixes this by skipping the first operand of SCOPE_REFs in
> contains_placeholder_p.

Code in gcc/ shouldn't refer to tree codes from cp-tree.def.

We probably shouldn't do the strong-eval-order transformation when 
processing_template_decl anyway.

> Successfully tested on x86_64-pc-linux-gnu.
> 
> 	PR c++/117158
> 
> gcc/ChangeLog:
> 
> 	* tree.cc (contains_placeholder_p): Skip the first operand of
> 	SCOPE_REFs.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/parse/crash77.C: New test.
> 
> ---
>   gcc/testsuite/g++.dg/parse/crash77.C | 13 +++++++++++++
>   gcc/tree.cc                          |  3 +++
>   2 files changed, 16 insertions(+)
>   create mode 100644 gcc/testsuite/g++.dg/parse/crash77.C
> 
> diff --git a/gcc/testsuite/g++.dg/parse/crash77.C b/gcc/testsuite/g++.dg/parse/crash77.C
> new file mode 100644
> index 00000000000..25a426fa6d6
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/parse/crash77.C
> @@ -0,0 +1,13 @@
> +// PR c++/117158
> +// { dg-do "compile" }
> +
> +struct Base {
> +  unsigned int *intarray;
> +};
> +
> +template <typename T>
> +struct Sub : public Base {
> +    bool Get(int i) {
> +	return (Base::intarray[++i] == 0);
> +    }
> +};
> diff --git a/gcc/tree.cc b/gcc/tree.cc
> index b4c059d3b0d..7f8911002d0 100644
> --- a/gcc/tree.cc
> +++ b/gcc/tree.cc
> @@ -4122,6 +4122,9 @@ contains_placeholder_p (const_tree exp)
>     if (!exp)
>       return false;
>   
> +  if (TREE_CODE (exp) == SCOPE_REF)
> +    exp = TREE_OPERAND (exp, 1);
> +
>     code = TREE_CODE (exp);
>     if (code == PLACEHOLDER_EXPR)
>       return true;
  

Patch

diff --git a/gcc/testsuite/g++.dg/parse/crash77.C b/gcc/testsuite/g++.dg/parse/crash77.C
new file mode 100644
index 00000000000..25a426fa6d6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/crash77.C
@@ -0,0 +1,13 @@ 
+// PR c++/117158
+// { dg-do "compile" }
+
+struct Base {
+  unsigned int *intarray;
+};
+
+template <typename T>
+struct Sub : public Base {
+    bool Get(int i) {
+	return (Base::intarray[++i] == 0);
+    }
+};
diff --git a/gcc/tree.cc b/gcc/tree.cc
index b4c059d3b0d..7f8911002d0 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -4122,6 +4122,9 @@  contains_placeholder_p (const_tree exp)
   if (!exp)
     return false;
 
+  if (TREE_CODE (exp) == SCOPE_REF)
+    exp = TREE_OPERAND (exp, 1);
+
   code = TREE_CODE (exp);
   if (code == PLACEHOLDER_EXPR)
     return true;