diff mbox series

c++: Diagnose a deduction guide in a wrong scope [PR91759]

Message ID 20200317084902.GX2156@tucnak
State New
Headers show
Series c++: Diagnose a deduction guide in a wrong scope [PR91759] | expand

Commit Message

Li, Pan2 via Gcc-patches March 17, 2020, 8:49 a.m. UTC
Hi!

The following testcase is accepts-invalid since r7-6608-ga56c0ac08242269b.
Before that change we had this
"deduction guide %qD must be declared in the same scope as %qT"
diagnostics for it, after the change it is expected to be diagnosed
in set_decl_namespace at the not_found: label in there.  On this testcase
nothing is diagnosed though, because set_decl_namespace isn't called at all,
as in_namespace is NULL.

The following patch restores the old warning but does it only in case we
don't call set_decl_namespace.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
Or do you prefer something different?

2020-03-17  Jakub Jelinek  <jakub@redhat.com>

	PR c++/91759
	* decl.c (grokfndecl): Restore old diagnostics about deduction
	guide declared in different scope if in_namespace is NULL_TREE.

	* g++.dg/cpp1z/class-deduction72.C: New test.


	Jakub

Comments

Li, Pan2 via Gcc-patches March 17, 2020, 7:54 p.m. UTC | #1
On 3/17/20 4:49 AM, Jakub Jelinek wrote:
> Hi!
> 
> The following testcase is accepts-invalid since r7-6608-ga56c0ac08242269b.
> Before that change we had this
> "deduction guide %qD must be declared in the same scope as %qT"
> diagnostics for it, after the change it is expected to be diagnosed
> in set_decl_namespace at the not_found: label in there.  On this testcase
> nothing is diagnosed though, because set_decl_namespace isn't called at all,
> as in_namespace is NULL.
> 
> The following patch restores the old warning but does it only in case we
> don't call set_decl_namespace.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
> Or do you prefer something different?

How about always diagnosing this here, and moving the deduction guide 
code in grokfndecl up above set_decl_namespace to avoid a duplicate 
diagnostic?

> 2020-03-17  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR c++/91759
> 	* decl.c (grokfndecl): Restore old diagnostics about deduction
> 	guide declared in different scope if in_namespace is NULL_TREE.
> 
> 	* g++.dg/cpp1z/class-deduction72.C: New test.
> 
> --- gcc/cp/decl.c.jj	2020-03-12 08:26:23.000000000 +0100
> +++ gcc/cp/decl.c	2020-03-16 16:25:02.142867924 +0100
> @@ -9644,6 +9644,15 @@ grokfndecl (tree ctype,
>   		    "namespace scope", decl);
>   	  return NULL_TREE;
>   	}
> +      tree type = TREE_TYPE (DECL_NAME (decl));
> +      if (in_namespace == NULL_TREE
> +	  && CP_DECL_CONTEXT (decl) != CP_TYPE_CONTEXT (type))
> +	{
> +	  error_at (location, "deduction guide %qD must be declared in the "
> +			      "same scope as %qT", decl, type);
> +	  inform (location_of (type), "  declared here");
> +	  return NULL_TREE;
> +	}
>         if (funcdef_flag)
>   	error_at (location,
>   		  "deduction guide %qD must not have a function body", decl);
> --- gcc/testsuite/g++.dg/cpp1z/class-deduction72.C.jj	2020-03-16 16:27:03.997068510 +0100
> +++ gcc/testsuite/g++.dg/cpp1z/class-deduction72.C	2020-03-16 16:28:21.241927835 +0100
> @@ -0,0 +1,11 @@
> +// PR c++/91759
> +// { dg-do compile { target c++17 } }
> +
> +namespace N {
> +  template <typename T>
> +  struct X{ X(int); };	// { dg-message "declared here" }
> +}
> +
> +using N::X;
> +
> +X(int) -> X<int>;	// { dg-error "must be declared in the same scope as" }
> 
> 	Jakub
>
Li, Pan2 via Gcc-patches March 17, 2020, 9:06 p.m. UTC | #2
On Tue, Mar 17, 2020 at 03:54:57PM -0400, Jason Merrill via Gcc-patches wrote:
> How about always diagnosing this here, and moving the deduction guide code
> in grokfndecl up above set_decl_namespace to avoid a duplicate diagnostic?

I've tried that as:
--- gcc/cp/decl.c.jj	2020-03-16 22:56:46.787172869 +0100
+++ gcc/cp/decl.c	2020-03-17 21:29:17.812732717 +0100
@@ -9506,6 +9506,27 @@ grokfndecl (tree ctype,
       inlinep &= ~8;
     }
 
+  if (deduction_guide_p (decl))
+    {
+      if (!DECL_NAMESPACE_SCOPE_P (decl))
+	{
+	  error_at (location, "deduction guide %qD must be declared at "
+		    "namespace scope", decl);
+	  return NULL_TREE;
+	}
+      tree type = TREE_TYPE (DECL_NAME (decl));
+      if (CP_DECL_CONTEXT (decl) != CP_TYPE_CONTEXT (type))
+	{
+	  error_at (location, "deduction guide %qD must be declared in the "
+			      "same scope as %qT", decl, type);
+	  inform (location_of (type), "  declared here");
+	  return NULL_TREE;
+	}
+      if (funcdef_flag)
+	error_at (location,
+		  "deduction guide %qD must not have a function body", decl);
+    }
+
   /* If this decl has namespace scope, set that up.  */
   if (in_namespace)
     set_decl_namespace (decl, in_namespace, friendp);
@@ -9636,20 +9657,8 @@ grokfndecl (tree ctype,
 	}
     }
 
-  if (deduction_guide_p (decl))
-    {
-      if (!DECL_NAMESPACE_SCOPE_P (decl))
-	{
-	  error_at (location, "deduction guide %qD must be declared at "
-		    "namespace scope", decl);
-	  return NULL_TREE;
-	}
-      if (funcdef_flag)
-	error_at (location,
-		  "deduction guide %qD must not have a function body", decl);
-    }
-  else if (IDENTIFIER_ANY_OP_P (DECL_NAME (decl))
-	   && !grok_op_properties (decl, /*complain=*/true))
+  if (IDENTIFIER_ANY_OP_P (DECL_NAME (decl))
+      && !grok_op_properties (decl, /*complain=*/true))
     return NULL_TREE;
   else if (UDLIT_OPER_P (DECL_NAME (decl)))
     {
--- gcc/testsuite/g++.dg/cpp1z/class-deduction9.C.jj	2020-01-12 11:54:37.126402652 +0100
+++ gcc/testsuite/g++.dg/cpp1z/class-deduction9.C	2020-03-17 21:29:53.842207083 +0100
@@ -10,7 +10,7 @@ namespace N {
 }
 
 template <class T>
-N::A(T) -> N::A<T>;	  // { dg-error "should have been declared inside .N" }
+N::A(T) -> N::A<T>;	  // { dg-error "must be declared in the same scope as" }
 
 namespace N {
   template <class T>
--- gcc/testsuite/g++.dg/cpp1z/class-deduction72.C.jj	2020-03-17 21:26:00.566610331 +0100
+++ gcc/testsuite/g++.dg/cpp1z/class-deduction72.C	2020-03-17 21:26:00.566610331 +0100
@@ -0,0 +1,11 @@
+// PR c++/91759
+// { dg-do compile { target c++17 } }
+
+namespace N {
+  template <typename T>
+  struct X{ X(int); };	// { dg-message "declared here" }
+}
+
+using N::X;
+
+X(int) -> X<int>;	// { dg-error "must be declared in the same scope as" }

but that fails with
Excess errors:
/usr/src/gcc/obj/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/stl_pair.h:459:40: error: deduction guide 'pair(_T1, _T2)-> std::pair<_T1, _T2>' must be declared in the same scope as 'std::pair<_T1, _T2>'
/usr/src/gcc/obj/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/stl_vector.h:1873:5: error: deduction guide 'vector(_InputIterator, _InputIterator, _Allocator)-> std::vector<_ValT, _Allocator>' must be declared in the same scope as 'std::vector<_Tp, _Alloc>'
on various testcases.

I've tried next:
--- gcc/cp/decl.c.jj	2020-03-16 22:56:46.787172869 +0100
+++ gcc/cp/decl.c	2020-03-17 22:00:13.897648589 +0100
@@ -9506,6 +9506,36 @@ grokfndecl (tree ctype,
       inlinep &= ~8;
     }
 
+  if (deduction_guide_p (decl))
+    {
+      if (!DECL_NAMESPACE_SCOPE_P (decl))
+	{
+	  error_at (location, "deduction guide %qD must be declared at "
+		    "namespace scope", decl);
+	  return NULL_TREE;
+	}
+      tree type = TREE_TYPE (DECL_NAME (decl));
+      tree ctx = NULL_TREE;
+      if (in_namespace)
+	ctx = ORIGINAL_NAMESPACE (in_namespace);
+      else if (!ctype)
+	ctx = current_decl_namespace ();
+      if (ctx)
+	ctx = FROB_CONTEXT (ctx);
+      if (SCOPE_FILE_SCOPE_P (ctx))
+	ctx = global_namespace;
+      if (CP_TYPE_CONTEXT (type) != ctx)
+	{
+	  error_at (location, "deduction guide %qD must be declared in the "
+			      "same scope as %qT", decl, type);
+	  inform (location_of (type), "  declared here");
+	  return NULL_TREE;
+	}
+      if (funcdef_flag)
+	error_at (location,
+		  "deduction guide %qD must not have a function body", decl);
+    }
+
   /* If this decl has namespace scope, set that up.  */
   if (in_namespace)
     set_decl_namespace (decl, in_namespace, friendp);
@@ -9636,20 +9666,8 @@ grokfndecl (tree ctype,
 	}
     }
 
-  if (deduction_guide_p (decl))
-    {
-      if (!DECL_NAMESPACE_SCOPE_P (decl))
-	{
-	  error_at (location, "deduction guide %qD must be declared at "
-		    "namespace scope", decl);
-	  return NULL_TREE;
-	}
-      if (funcdef_flag)
-	error_at (location,
-		  "deduction guide %qD must not have a function body", decl);
-    }
-  else if (IDENTIFIER_ANY_OP_P (DECL_NAME (decl))
-	   && !grok_op_properties (decl, /*complain=*/true))
+  if (IDENTIFIER_ANY_OP_P (DECL_NAME (decl))
+      && !grok_op_properties (decl, /*complain=*/true))
     return NULL_TREE;
   else if (UDLIT_OPER_P (DECL_NAME (decl)))
     {
--- gcc/testsuite/g++.dg/cpp1z/class-deduction72.C.jj	2020-03-17 21:26:00.566610331 +0100
+++ gcc/testsuite/g++.dg/cpp1z/class-deduction72.C	2020-03-17 21:26:00.566610331 +0100
@@ -0,0 +1,11 @@
+// PR c++/91759
+// { dg-do compile { target c++17 } }
+
+namespace N {
+  template <typename T>
+  struct X{ X(int); };	// { dg-message "declared here" }
+}
+
+using N::X;
+
+X(int) -> X<int>;	// { dg-error "must be declared in the same scope as" }
--- gcc/testsuite/g++.dg/cpp1z/class-deduction9.C.jj	2020-01-12 11:54:37.126402652 +0100
+++ gcc/testsuite/g++.dg/cpp1z/class-deduction9.C	2020-03-17 21:29:53.842207083 +0100
@@ -10,7 +10,7 @@ namespace N {
 }
 
 template <class T>
-N::A(T) -> N::A<T>;	  // { dg-error "should have been declared inside .N" }
+N::A(T) -> N::A<T>;	  // { dg-error "must be declared in the same scope as" }
 
 namespace N {
   template <class T>

but that FAILs the class-deduction9.C test with the adjustment,
reports the older "should have been"... error instead, because the computed
ctx is the N namespace, which is also what set_decl_namespace sets, but then
it fails some lookup and emits this message.

	Jakub
Li, Pan2 via Gcc-patches March 17, 2020, 9:36 p.m. UTC | #3
On 3/17/20 5:06 PM, Jakub Jelinek wrote:
> On Tue, Mar 17, 2020 at 03:54:57PM -0400, Jason Merrill via Gcc-patches wrote:
>> How about always diagnosing this here, and moving the deduction guide code
>> in grokfndecl up above set_decl_namespace to avoid a duplicate diagnostic?
> 
> I've tried that as:
> --- gcc/cp/decl.c.jj	2020-03-16 22:56:46.787172869 +0100
> +++ gcc/cp/decl.c	2020-03-17 21:29:17.812732717 +0100
> @@ -9506,6 +9506,27 @@ grokfndecl (tree ctype,
>         inlinep &= ~8;
>       }
>   
> +  if (deduction_guide_p (decl))
> +    {
> +      if (!DECL_NAMESPACE_SCOPE_P (decl))
> +	{
> +	  error_at (location, "deduction guide %qD must be declared at "
> +		    "namespace scope", decl);
> +	  return NULL_TREE;
> +	}
> +      tree type = TREE_TYPE (DECL_NAME (decl));
> +      if (CP_DECL_CONTEXT (decl) != CP_TYPE_CONTEXT (type))
> +	{
> +	  error_at (location, "deduction guide %qD must be declared in the "
> +			      "same scope as %qT", decl, type);
> +	  inform (location_of (type), "  declared here");
> +	  return NULL_TREE;
> +	}
> +      if (funcdef_flag)
> +	error_at (location,
> +		  "deduction guide %qD must not have a function body", decl);
> +    }
> +
>     /* If this decl has namespace scope, set that up.  */
>     if (in_namespace)
>       set_decl_namespace (decl, in_namespace, friendp);
> @@ -9636,20 +9657,8 @@ grokfndecl (tree ctype,
>   	}
>       }
>   
> -  if (deduction_guide_p (decl))
> -    {
> -      if (!DECL_NAMESPACE_SCOPE_P (decl))
> -	{
> -	  error_at (location, "deduction guide %qD must be declared at "
> -		    "namespace scope", decl);
> -	  return NULL_TREE;
> -	}
> -      if (funcdef_flag)
> -	error_at (location,
> -		  "deduction guide %qD must not have a function body", decl);
> -    }
> -  else if (IDENTIFIER_ANY_OP_P (DECL_NAME (decl))
> -	   && !grok_op_properties (decl, /*complain=*/true))
> +  if (IDENTIFIER_ANY_OP_P (DECL_NAME (decl))
> +      && !grok_op_properties (decl, /*complain=*/true))
>       return NULL_TREE;
>     else if (UDLIT_OPER_P (DECL_NAME (decl)))
>       {
> --- gcc/testsuite/g++.dg/cpp1z/class-deduction9.C.jj	2020-01-12 11:54:37.126402652 +0100
> +++ gcc/testsuite/g++.dg/cpp1z/class-deduction9.C	2020-03-17 21:29:53.842207083 +0100
> @@ -10,7 +10,7 @@ namespace N {
>   }
>   
>   template <class T>
> -N::A(T) -> N::A<T>;	  // { dg-error "should have been declared inside .N" }
> +N::A(T) -> N::A<T>;	  // { dg-error "must be declared in the same scope as" }
>   
>   namespace N {
>     template <class T>
> --- gcc/testsuite/g++.dg/cpp1z/class-deduction72.C.jj	2020-03-17 21:26:00.566610331 +0100
> +++ gcc/testsuite/g++.dg/cpp1z/class-deduction72.C	2020-03-17 21:26:00.566610331 +0100
> @@ -0,0 +1,11 @@
> +// PR c++/91759
> +// { dg-do compile { target c++17 } }
> +
> +namespace N {
> +  template <typename T>
> +  struct X{ X(int); };	// { dg-message "declared here" }
> +}
> +
> +using N::X;
> +
> +X(int) -> X<int>;	// { dg-error "must be declared in the same scope as" }
> 
> but that fails with
> Excess errors:
> /usr/src/gcc/obj/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/stl_pair.h:459:40: error: deduction guide 'pair(_T1, _T2)-> std::pair<_T1, _T2>' must be declared in the same scope as 'std::pair<_T1, _T2>'
> /usr/src/gcc/obj/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/stl_vector.h:1873:5: error: deduction guide 'vector(_InputIterator, _InputIterator, _Allocator)-> std::vector<_ValT, _Allocator>' must be declared in the same scope as 'std::vector<_Tp, _Alloc>'
> on various testcases.
> 
> I've tried next:
> --- gcc/cp/decl.c.jj	2020-03-16 22:56:46.787172869 +0100
> +++ gcc/cp/decl.c	2020-03-17 22:00:13.897648589 +0100
> @@ -9506,6 +9506,36 @@ grokfndecl (tree ctype,
>         inlinep &= ~8;
>       }
>   
> +  if (deduction_guide_p (decl))
> +    {
> +      if (!DECL_NAMESPACE_SCOPE_P (decl))
> +	{
> +	  error_at (location, "deduction guide %qD must be declared at "
> +		    "namespace scope", decl);
> +	  return NULL_TREE;
> +	}
> +      tree type = TREE_TYPE (DECL_NAME (decl));
> +      tree ctx = NULL_TREE;
> +      if (in_namespace)
> +	ctx = ORIGINAL_NAMESPACE (in_namespace);
> +      else if (!ctype)
> +	ctx = current_decl_namespace ();
> +      if (ctx)
> +	ctx = FROB_CONTEXT (ctx);
> +      if (SCOPE_FILE_SCOPE_P (ctx))
> +	ctx = global_namespace;
> +      if (CP_TYPE_CONTEXT (type) != ctx)
> +	{
> +	  error_at (location, "deduction guide %qD must be declared in the "
> +			      "same scope as %qT", decl, type);
> +	  inform (location_of (type), "  declared here");
> +	  return NULL_TREE;
> +	}
> +      if (funcdef_flag)
> +	error_at (location,
> +		  "deduction guide %qD must not have a function body", decl);
> +    }
> +
>     /* If this decl has namespace scope, set that up.  */
>     if (in_namespace)
>       set_decl_namespace (decl, in_namespace, friendp);
> @@ -9636,20 +9666,8 @@ grokfndecl (tree ctype,
>   	}
>       }
>   
> -  if (deduction_guide_p (decl))
> -    {
> -      if (!DECL_NAMESPACE_SCOPE_P (decl))
> -	{
> -	  error_at (location, "deduction guide %qD must be declared at "
> -		    "namespace scope", decl);
> -	  return NULL_TREE;
> -	}
> -      if (funcdef_flag)
> -	error_at (location,
> -		  "deduction guide %qD must not have a function body", decl);
> -    }
> -  else if (IDENTIFIER_ANY_OP_P (DECL_NAME (decl))
> -	   && !grok_op_properties (decl, /*complain=*/true))
> +  if (IDENTIFIER_ANY_OP_P (DECL_NAME (decl))
> +      && !grok_op_properties (decl, /*complain=*/true))
>       return NULL_TREE;
>     else if (UDLIT_OPER_P (DECL_NAME (decl)))
>       {
> --- gcc/testsuite/g++.dg/cpp1z/class-deduction72.C.jj	2020-03-17 21:26:00.566610331 +0100
> +++ gcc/testsuite/g++.dg/cpp1z/class-deduction72.C	2020-03-17 21:26:00.566610331 +0100
> @@ -0,0 +1,11 @@
> +// PR c++/91759
> +// { dg-do compile { target c++17 } }
> +
> +namespace N {
> +  template <typename T>
> +  struct X{ X(int); };	// { dg-message "declared here" }
> +}
> +
> +using N::X;
> +
> +X(int) -> X<int>;	// { dg-error "must be declared in the same scope as" }
> --- gcc/testsuite/g++.dg/cpp1z/class-deduction9.C.jj	2020-01-12 11:54:37.126402652 +0100
> +++ gcc/testsuite/g++.dg/cpp1z/class-deduction9.C	2020-03-17 21:29:53.842207083 +0100
> @@ -10,7 +10,7 @@ namespace N {
>   }
>   
>   template <class T>
> -N::A(T) -> N::A<T>;	  // { dg-error "should have been declared inside .N" }
> +N::A(T) -> N::A<T>;	  // { dg-error "must be declared in the same scope as" }
>   
>   namespace N {
>     template <class T>
> 
> but that FAILs the class-deduction9.C test with the adjustment,
> reports the older "should have been"... error instead, because the computed
> ctx is the N namespace, which is also what set_decl_namespace sets, but then
> it fails some lookup and emits this message.

Let's go with your earlier patch, then.  Thanks.

Jason
diff mbox series

Patch

--- gcc/cp/decl.c.jj	2020-03-12 08:26:23.000000000 +0100
+++ gcc/cp/decl.c	2020-03-16 16:25:02.142867924 +0100
@@ -9644,6 +9644,15 @@  grokfndecl (tree ctype,
 		    "namespace scope", decl);
 	  return NULL_TREE;
 	}
+      tree type = TREE_TYPE (DECL_NAME (decl));
+      if (in_namespace == NULL_TREE
+	  && CP_DECL_CONTEXT (decl) != CP_TYPE_CONTEXT (type))
+	{
+	  error_at (location, "deduction guide %qD must be declared in the "
+			      "same scope as %qT", decl, type);
+	  inform (location_of (type), "  declared here");
+	  return NULL_TREE;
+	}
       if (funcdef_flag)
 	error_at (location,
 		  "deduction guide %qD must not have a function body", decl);
--- gcc/testsuite/g++.dg/cpp1z/class-deduction72.C.jj	2020-03-16 16:27:03.997068510 +0100
+++ gcc/testsuite/g++.dg/cpp1z/class-deduction72.C	2020-03-16 16:28:21.241927835 +0100
@@ -0,0 +1,11 @@ 
+// PR c++/91759
+// { dg-do compile { target c++17 } }
+
+namespace N {
+  template <typename T>
+  struct X{ X(int); };	// { dg-message "declared here" }
+}
+
+using N::X;
+
+X(int) -> X<int>;	// { dg-error "must be declared in the same scope as" }