c++: constrained partial spec using qualified name [PR92944]

Message ID 20220126174919.2775070-1-ppalka@redhat.com
State New
Headers
Series c++: constrained partial spec using qualified name [PR92944] |

Commit Message

Patrick Palka Jan. 26, 2022, 5:49 p.m. UTC
  In the nested_name_specifier branch within cp_parser_class_head, we need
to update TYPE with the result of maybe_process_partial_specialization
just like we do in the template_id_p branch.

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?

	PR c++/92944

gcc/cp/ChangeLog:

	* parser.cc (cp_parser_class_head): Update TYPE with the result
	of maybe_process_partial_specialization in the
	nested_name_specifier branch too.  Refactor nearby code to
	accomodate that maybe_process_partial_specialization returns a
	_TYPE, not a TYPE_DECL, and eliminate local variable CLASS_TYPE.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp2a/concepts-partial-spec10.C: New test.
---
 gcc/cp/parser.cc                               | 18 +++++++-----------
 .../g++.dg/cpp2a/concepts-partial-spec10.C     |  6 ++++++
 2 files changed, 13 insertions(+), 11 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec10.C
  

Comments

Jason Merrill Jan. 27, 2022, 3:34 p.m. UTC | #1
On 1/26/22 12:49, Patrick Palka wrote:
> In the nested_name_specifier branch within cp_parser_class_head, we need
> to update TYPE with the result of maybe_process_partial_specialization
> just like we do in the template_id_p branch.
> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk?

OK.

> 	PR c++/92944
> 
> gcc/cp/ChangeLog:
> 
> 	* parser.cc (cp_parser_class_head): Update TYPE with the result
> 	of maybe_process_partial_specialization in the
> 	nested_name_specifier branch too.  Refactor nearby code to
> 	accomodate that maybe_process_partial_specialization returns a
> 	_TYPE, not a TYPE_DECL, and eliminate local variable CLASS_TYPE.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/cpp2a/concepts-partial-spec10.C: New test.
> ---
>   gcc/cp/parser.cc                               | 18 +++++++-----------
>   .../g++.dg/cpp2a/concepts-partial-spec10.C     |  6 ++++++
>   2 files changed, 13 insertions(+), 11 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec10.C
> 
> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> index ed219d79dc9..aa1768ffab1 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -26534,7 +26534,7 @@ cp_parser_class_head (cp_parser* parser,
>       }
>     else if (nested_name_specifier)
>       {
> -      tree class_type;
> +      type = TREE_TYPE (type);
>   
>         /* Given:
>   
> @@ -26544,31 +26544,27 @@ cp_parser_class_head (cp_parser* parser,
>   	 we will get a TYPENAME_TYPE when processing the definition of
>   	 `S::T'.  We need to resolve it to the actual type before we
>   	 try to define it.  */
> -      if (TREE_CODE (TREE_TYPE (type)) == TYPENAME_TYPE)
> +      if (TREE_CODE (type) == TYPENAME_TYPE)
>   	{
> -	  class_type = resolve_typename_type (TREE_TYPE (type),
> -					      /*only_current_p=*/false);
> -	  if (TREE_CODE (class_type) != TYPENAME_TYPE)
> -	    type = TYPE_NAME (class_type);
> -	  else
> +	  type = resolve_typename_type (type, /*only_current_p=*/false);
> +	  if (TREE_CODE (type) == TYPENAME_TYPE)
>   	    {
>   	      cp_parser_error (parser, "could not resolve typename type");
>   	      type = error_mark_node;
>   	    }
>   	}
>   
> -      if (maybe_process_partial_specialization (TREE_TYPE (type))
> -	  == error_mark_node)
> +      type = maybe_process_partial_specialization (type);
> +      if (type == error_mark_node)
>   	{
>   	  type = NULL_TREE;
>   	  goto done;
>   	}
>   
> -      class_type = current_class_type;
>         /* Enter the scope indicated by the nested-name-specifier.  */
>         pushed_scope = push_scope (nested_name_specifier);
>         /* Get the canonical version of this type.  */
> -      type = TYPE_MAIN_DECL (TREE_TYPE (type));
> +      type = TYPE_MAIN_DECL (type);
>         /* Call push_template_decl if it seems like we should be defining a
>   	 template either from the template headers or the type we're
>   	 defining, so that we diagnose both extra and missing headers.  */
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec10.C b/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec10.C
> new file mode 100644
> index 00000000000..8504a055ac5
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec10.C
> @@ -0,0 +1,6 @@
> +// PR c++/92944
> +// { dg-do compile { target c++20 } }
> +
> +namespace ns { template<class T> struct A { }; }
> +template<class T> requires true struct ns::A<T> { };
> +template<class T> requires false struct ns::A<T> { };
  

Patch

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index ed219d79dc9..aa1768ffab1 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -26534,7 +26534,7 @@  cp_parser_class_head (cp_parser* parser,
     }
   else if (nested_name_specifier)
     {
-      tree class_type;
+      type = TREE_TYPE (type);
 
       /* Given:
 
@@ -26544,31 +26544,27 @@  cp_parser_class_head (cp_parser* parser,
 	 we will get a TYPENAME_TYPE when processing the definition of
 	 `S::T'.  We need to resolve it to the actual type before we
 	 try to define it.  */
-      if (TREE_CODE (TREE_TYPE (type)) == TYPENAME_TYPE)
+      if (TREE_CODE (type) == TYPENAME_TYPE)
 	{
-	  class_type = resolve_typename_type (TREE_TYPE (type),
-					      /*only_current_p=*/false);
-	  if (TREE_CODE (class_type) != TYPENAME_TYPE)
-	    type = TYPE_NAME (class_type);
-	  else
+	  type = resolve_typename_type (type, /*only_current_p=*/false);
+	  if (TREE_CODE (type) == TYPENAME_TYPE)
 	    {
 	      cp_parser_error (parser, "could not resolve typename type");
 	      type = error_mark_node;
 	    }
 	}
 
-      if (maybe_process_partial_specialization (TREE_TYPE (type))
-	  == error_mark_node)
+      type = maybe_process_partial_specialization (type);
+      if (type == error_mark_node)
 	{
 	  type = NULL_TREE;
 	  goto done;
 	}
 
-      class_type = current_class_type;
       /* Enter the scope indicated by the nested-name-specifier.  */
       pushed_scope = push_scope (nested_name_specifier);
       /* Get the canonical version of this type.  */
-      type = TYPE_MAIN_DECL (TREE_TYPE (type));
+      type = TYPE_MAIN_DECL (type);
       /* Call push_template_decl if it seems like we should be defining a
 	 template either from the template headers or the type we're
 	 defining, so that we diagnose both extra and missing headers.  */
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec10.C b/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec10.C
new file mode 100644
index 00000000000..8504a055ac5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec10.C
@@ -0,0 +1,6 @@ 
+// PR c++/92944
+// { dg-do compile { target c++20 } }
+
+namespace ns { template<class T> struct A { }; }
+template<class T> requires true struct ns::A<T> { };
+template<class T> requires false struct ns::A<T> { };