public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] Fix behavior of using enum in dependent contexts [PR105787]
@ 2022-06-06 19:39 Michael Colavita
  2022-06-06 21:48 ` Jason Merrill
  0 siblings, 1 reply; 2+ messages in thread
From: Michael Colavita @ 2022-06-06 19:39 UTC (permalink / raw)
  To: gcc-patches

Per #105787, "using enum" in a dependent context leads to an ICE. This
is because the type substitution logic doesn't properly juggle the
context and abstract origin for CONST_DECLs introduced via using enum.
When we are performing type substitution on the CONST_DECL, we want to
do so in the context of the original enum type. When we return the
resulting value, we want to replace the context with the class in which
the CONST_DECL exists. This amounts to using the abstract origin for the
type substitution, and performing the same clone/abstract origin update
as we do for parsing "using enum" in non-dependent contexts.

PR c++/105787 - internal compiler error: tree check: expected enumeral_type, have record_type in tsubst_copy

        PR c++/105787

gcc/cp/ChangeLog:

        * pt.cc (tsubst_copy): Handle CONST_DECLs involving "using enum"
          in dependent contexts.

gcc/testsuite/ChangeLog:

        * g++.dg/cpp2a/using-enum-10.C: New test.
        * g++.dg/cpp2a/using-enum-11.C: New test.
---
 gcc/cp/pt.cc                               | 24 +++++++++++++-
 gcc/testsuite/g++.dg/cpp2a/using-enum-10.C | 35 ++++++++++++++++++++
 gcc/testsuite/g++.dg/cpp2a/using-enum-11.C | 38 ++++++++++++++++++++++
 3 files changed, 96 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/using-enum-10.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/using-enum-11.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 6de8e496859..c11c682ded7 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -16892,6 +16892,7 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
       {
 	tree enum_type;
 	tree v;
+	tree original;
 
 	if (DECL_TEMPLATE_PARM_P (t))
 	  return tsubst_copy (DECL_INITIAL (t), args, complain, in_decl);
@@ -16903,6 +16904,14 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	if (args == NULL_TREE)
 	  return scalar_constant_value (t);
 
+	/* When the CONST_DECL is a class-scope clone from using enum, we want
+	   to perform the type substitution in the context of the original enum
+	   (the abstract origin), but return a value in the context of the
+	   class. */
+	original = t;
+	if (CONST_DECL_USING_P (original))
+	  t = DECL_ABSTRACT_ORIGIN (original);
+
 	/* Unfortunately, we cannot just call lookup_name here.
 	   Consider:
 
@@ -16921,7 +16930,20 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	     v != NULL_TREE;
 	     v = TREE_CHAIN (v))
 	  if (TREE_PURPOSE (v) == DECL_NAME (t))
-	    return TREE_VALUE (v);
+	    {
+	      tree value = TREE_VALUE (v);
+	      if (!CONST_DECL_USING_P (original))
+		return value;
+	      else
+		{
+		  value = copy_decl (value);
+		  DECL_ARTIFICIAL (value) = true;
+		  DECL_CONTEXT (value) = DECL_CONTEXT (original);
+		  DECL_IGNORED_P (value) = true;
+		  DECL_ABSTRACT_ORIGIN (value) = DECL_ABSTRACT_ORIGIN (original);
+		  return value;
+		}
+	    }
 
 	  /* We didn't find the name.  That should never happen; if
 	     name-lookup found it during preliminary parsing, we
diff --git a/gcc/testsuite/g++.dg/cpp2a/using-enum-10.C b/gcc/testsuite/g++.dg/cpp2a/using-enum-10.C
new file mode 100644
index 00000000000..ab4cb648e03
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/using-enum-10.C
@@ -0,0 +1,35 @@
+// PR c++/105787
+// { dg-do compile { target c++20 } }
+
+enum class fruit { orange, apple };
+
+struct A {
+public:
+  using enum fruit;
+private:
+};
+
+struct B {
+protected:
+  using enum fruit;
+public:
+};
+
+struct C {
+private:
+  using enum fruit;
+public:
+};
+
+template <int> struct D {
+  char a1 = (char) A::orange;
+  char a2 = (char) A::apple;
+  char b1 = (char) B::orange; // { dg-error "protected" }
+  char b2 = (char) B::apple; // { dg-error "protected" }
+  char c1 = (char) C::orange; // { dg-error "private" }
+  char c2 = (char) C::apple; // { dg-error "private" }
+};
+
+int main() {
+    D<0> d;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/using-enum-11.C b/gcc/testsuite/g++.dg/cpp2a/using-enum-11.C
new file mode 100644
index 00000000000..1899e05c68d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/using-enum-11.C
@@ -0,0 +1,38 @@
+// PR c++/105787
+// { dg-do compile { target c++20 } }
+
+enum class fruit { orange, apple };
+
+struct A {
+public:
+  using fruit::apple;
+  using fruit::orange;
+private:
+};
+
+struct B {
+protected:
+  using fruit::apple;
+  using fruit::orange;
+public:
+};
+
+struct C {
+private:
+  using fruit::apple;
+  using fruit::orange;
+public:
+};
+
+template <int> struct D {
+  char a1 = (char) A::orange;
+  char a2 = (char) A::apple;
+  char b1 = (char) B::orange; // { dg-error "protected" }
+  char b2 = (char) B::apple; // { dg-error "protected" }
+  char c1 = (char) C::orange; // { dg-error "private" }
+  char c2 = (char) C::apple; // { dg-error "private" }
+};
+
+int main() {
+    D<0> d;
+}
-- 
2.23.0


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PATCH] Fix behavior of using enum in dependent contexts [PR105787]
  2022-06-06 19:39 [PATCH] Fix behavior of using enum in dependent contexts [PR105787] Michael Colavita
@ 2022-06-06 21:48 ` Jason Merrill
  0 siblings, 0 replies; 2+ messages in thread
From: Jason Merrill @ 2022-06-06 21:48 UTC (permalink / raw)
  To: Michael Colavita, gcc-patches

On 6/6/22 15:39, Michael Colavita via Gcc-patches wrote:
> Per #105787, "using enum" in a dependent context leads to an ICE. This
> is because the type substitution logic doesn't properly juggle the
> context and abstract origin for CONST_DECLs introduced via using enum.
> When we are performing type substitution on the CONST_DECL, we want to
> do so in the context of the original enum type. When we return the
> resulting value, we want to replace the context with the class in which
> the CONST_DECL exists. This amounts to using the abstract origin for the
> type substitution, and performing the same clone/abstract origin update
> as we do for parsing "using enum" in non-dependent contexts.

Thanks for the patch!  It looks like you don't have a copyright 
assignment on file, so we need you to certify the DCO in the commit 
message of your patch; see

   https://gcc.gnu.org/contribute.html#legal

for more details.

Also, per the section on e-mail subject lines further down in that page, 
you need a "c++:" tag in your subject line.

> PR c++/105787 - internal compiler error: tree check: expected enumeral_type, have record_type in tsubst_copy
> 
>          PR c++/105787
> 
> gcc/cp/ChangeLog:
> 
>          * pt.cc (tsubst_copy): Handle CONST_DECLs involving "using enum"
>            in dependent contexts.
> 
> gcc/testsuite/ChangeLog:
> 
>          * g++.dg/cpp2a/using-enum-10.C: New test.
>          * g++.dg/cpp2a/using-enum-11.C: New test.
> ---
>   gcc/cp/pt.cc                               | 24 +++++++++++++-
>   gcc/testsuite/g++.dg/cpp2a/using-enum-10.C | 35 ++++++++++++++++++++
>   gcc/testsuite/g++.dg/cpp2a/using-enum-11.C | 38 ++++++++++++++++++++++
>   3 files changed, 96 insertions(+), 1 deletion(-)
>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/using-enum-10.C
>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/using-enum-11.C
> 
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 6de8e496859..c11c682ded7 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -16892,6 +16892,7 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
>         {
>   	tree enum_type;
>   	tree v;
> +	tree original;

Note that existing variable declarations at the beginning of the block 
are vestiges of when GCC was written in C; now that we can write C++11, 
it's better to declare variables at the point when they are first 
initialized.

>   	if (DECL_TEMPLATE_PARM_P (t))
>   	  return tsubst_copy (DECL_INITIAL (t), args, complain, in_decl);
> @@ -16903,6 +16904,14 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
>   	if (args == NULL_TREE)
>   	  return scalar_constant_value (t);
>   
> +	/* When the CONST_DECL is a class-scope clone from using enum, we want
> +	   to perform the type substitution in the context of the original enum
> +	   (the abstract origin), but return a value in the context of the
> +	   class. */
> +	original = t;
> +	if (CONST_DECL_USING_P (original))
> +	  t = DECL_ABSTRACT_ORIGIN (original);
> +
>   	/* Unfortunately, we cannot just call lookup_name here.
>   	   Consider:
>   
> @@ -16921,7 +16930,20 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
>   	     v != NULL_TREE;
>   	     v = TREE_CHAIN (v))
>   	  if (TREE_PURPOSE (v) == DECL_NAME (t))
> -	    return TREE_VALUE (v);
> +	    {
> +	      tree value = TREE_VALUE (v);
> +	      if (!CONST_DECL_USING_P (original))
> +		return value;
> +	      else
> +		{
> +		  value = copy_decl (value);
> +		  DECL_ARTIFICIAL (value) = true;
> +		  DECL_CONTEXT (value) = DECL_CONTEXT (original);
> +		  DECL_IGNORED_P (value) = true;
> +		  DECL_ABSTRACT_ORIGIN (value) = DECL_ABSTRACT_ORIGIN (original);
> +		  return value;

We shouldn't be creating new decls in tsubst_copy, which is called for 
uses of a decl in an expression; if instantiate_class_template (calling 
tsubst_decl) is doing something wrong when instantiating the clone, 
that's the place to fix it.

> +		}
> +	    }
>   
>   	  /* We didn't find the name.  That should never happen; if
>   	     name-lookup found it during preliminary parsing, we
> diff --git a/gcc/testsuite/g++.dg/cpp2a/using-enum-10.C b/gcc/testsuite/g++.dg/cpp2a/using-enum-10.C
> new file mode 100644
> index 00000000000..ab4cb648e03
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/using-enum-10.C
> @@ -0,0 +1,35 @@
> +// PR c++/105787
> +// { dg-do compile { target c++20 } }
> +
> +enum class fruit { orange, apple };
> +
> +struct A {
> +public:
> +  using enum fruit;
> +private:
> +};
> +
> +struct B {
> +protected:
> +  using enum fruit;
> +public:
> +};
> +
> +struct C {
> +private:
> +  using enum fruit;
> +public:
> +};
> +
> +template <int> struct D {
> +  char a1 = (char) A::orange;
> +  char a2 = (char) A::apple;
> +  char b1 = (char) B::orange; // { dg-error "protected" }
> +  char b2 = (char) B::apple; // { dg-error "protected" }
> +  char c1 = (char) C::orange; // { dg-error "private" }
> +  char c2 = (char) C::apple; // { dg-error "private" }
> +};
> +
> +int main() {
> +    D<0> d;
> +}
> diff --git a/gcc/testsuite/g++.dg/cpp2a/using-enum-11.C b/gcc/testsuite/g++.dg/cpp2a/using-enum-11.C
> new file mode 100644
> index 00000000000..1899e05c68d
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/using-enum-11.C
> @@ -0,0 +1,38 @@
> +// PR c++/105787
> +// { dg-do compile { target c++20 } }
> +
> +enum class fruit { orange, apple };
> +
> +struct A {
> +public:
> +  using fruit::apple;
> +  using fruit::orange;
> +private:
> +};
> +
> +struct B {
> +protected:
> +  using fruit::apple;
> +  using fruit::orange;
> +public:
> +};
> +
> +struct C {
> +private:
> +  using fruit::apple;
> +  using fruit::orange;
> +public:
> +};
> +
> +template <int> struct D {
> +  char a1 = (char) A::orange;
> +  char a2 = (char) A::apple;
> +  char b1 = (char) B::orange; // { dg-error "protected" }
> +  char b2 = (char) B::apple; // { dg-error "protected" }
> +  char c1 = (char) C::orange; // { dg-error "private" }
> +  char c2 = (char) C::apple; // { dg-error "private" }
> +};
> +
> +int main() {
> +    D<0> d;
> +}


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2022-06-06 21:48 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-06 19:39 [PATCH] Fix behavior of using enum in dependent contexts [PR105787] Michael Colavita
2022-06-06 21:48 ` Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).