c++: Check uniqueness of concepts/variable templates [PR94553]

Message ID 20200626192641.1193799-1-polacek@redhat.com
State New
Headers show
Series
  • c++: Check uniqueness of concepts/variable templates [PR94553]
Related show

Commit Message

Peter Bergner via Gcc-patches June 26, 2020, 7:26 p.m.
This patch wraps up PR94553.  Variable template names have no C
compatibility implications so they should be unique in their
declarative region.  It occurred to me that this applies to concepts
as well.  This is not specified in [basic.scope.declarative]/4.2
but that seems like a bug in the standard.

I couldn't use variable_template_p because that uses PRIMARY_TEMPLATE_P
which uses DECL_PRIMARY_TEMPLATE and that might not have been set up yet
(push_template_decl hasn't yet been called).  PRIMARY_TEMPLATE_P is
important to distinguish between a variable template and a variable in a
function template.  But I think we don't have to worry about that in
duplicate_decls: a template declaration cannot appear at block scope,
and additional checks in duplicate_decls suggest that it won't ever
see a TEMPLATE_DECL for a variable in a function template.  So
checking that the DECL_TEMPLATE_RESULT is a VAR_DECL seems to be fine.
I could have added a default argument to variable_template_p too to
avoid checking PRIMARY_TEMPLATE_P but it didn't seem worth the effort.

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

gcc/cp/ChangeLog:

	PR c++/94553
	* decl.c (duplicate_decls): Make sure a concept or a variable
	template is unique in its declarative region.

gcc/testsuite/ChangeLog:

	PR c++/94553
	* g++.dg/cpp1y/pr68578.C: Adjust dg-error.
	* g++.dg/cpp1y/var-templ66.C: New test.
	* g++.dg/cpp2a/concepts-redecl1.C: New test.
---
 gcc/cp/decl.c                                 | 12 +++++++++++-
 gcc/testsuite/g++.dg/cpp1y/pr68578.C          |  2 +-
 gcc/testsuite/g++.dg/cpp1y/var-templ66.C      |  7 +++++++
 gcc/testsuite/g++.dg/cpp2a/concepts-redecl1.C |  7 +++++++
 4 files changed, 26 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/var-templ66.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-redecl1.C


base-commit: b3d77404c060c0d65d8d4c97254995737d0fc032
-- 
Marek Polacek • Red Hat, Inc. • 300 A St, Boston, MA

Comments

Peter Bergner via Gcc-patches June 29, 2020, 5 a.m. | #1
On 6/26/20 3:26 PM, Marek Polacek wrote:
> This patch wraps up PR94553.  Variable template names have no C

> compatibility implications so they should be unique in their

> declarative region.  It occurred to me that this applies to concepts

> as well.  This is not specified in [basic.scope.declarative]/4.2

> but that seems like a bug in the standard.

> 

> I couldn't use variable_template_p because that uses PRIMARY_TEMPLATE_P

> which uses DECL_PRIMARY_TEMPLATE and that might not have been set up yet

> (push_template_decl hasn't yet been called).  PRIMARY_TEMPLATE_P is

> important to distinguish between a variable template and a variable in a

> function template.  But I think we don't have to worry about that in

> duplicate_decls: a template declaration cannot appear at block scope,

> and additional checks in duplicate_decls suggest that it won't ever

> see a TEMPLATE_DECL for a variable in a function template.  So

> checking that the DECL_TEMPLATE_RESULT is a VAR_DECL seems to be fine.

> I could have added a default argument to variable_template_p too to

> avoid checking PRIMARY_TEMPLATE_P but it didn't seem worth the effort.

> 

> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?


OK.

> gcc/cp/ChangeLog:

> 

> 	PR c++/94553

> 	* decl.c (duplicate_decls): Make sure a concept or a variable

> 	template is unique in its declarative region.

> 

> gcc/testsuite/ChangeLog:

> 

> 	PR c++/94553

> 	* g++.dg/cpp1y/pr68578.C: Adjust dg-error.

> 	* g++.dg/cpp1y/var-templ66.C: New test.

> 	* g++.dg/cpp2a/concepts-redecl1.C: New test.

> ---

>   gcc/cp/decl.c                                 | 12 +++++++++++-

>   gcc/testsuite/g++.dg/cpp1y/pr68578.C          |  2 +-

>   gcc/testsuite/g++.dg/cpp1y/var-templ66.C      |  7 +++++++

>   gcc/testsuite/g++.dg/cpp2a/concepts-redecl1.C |  7 +++++++

>   4 files changed, 26 insertions(+), 2 deletions(-)

>   create mode 100644 gcc/testsuite/g++.dg/cpp1y/var-templ66.C

>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-redecl1.C

> 

> diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c

> index 3afad5ca805..45c871af741 100644

> --- a/gcc/cp/decl.c

> +++ b/gcc/cp/decl.c

> @@ -1679,6 +1679,16 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)

>         else if (DECL_TYPE_TEMPLATE_P (olddecl)

>   	       || DECL_TYPE_TEMPLATE_P (newdecl))

>   	/* Class template conflicts.  */;

> +      else if ((TREE_CODE (olddecl) == TEMPLATE_DECL

> +		&& DECL_TEMPLATE_RESULT (olddecl)

> +		&& TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)) == VAR_DECL)

> +	       || (TREE_CODE (newdecl) == TEMPLATE_DECL

> +		   && DECL_TEMPLATE_RESULT (newdecl)

> +		   && TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == VAR_DECL))

> +	/* Variable template conflicts.  */;

> +      else if (concept_definition_p (olddecl)

> +	       || concept_definition_p (newdecl))

> +	/* Concept conflicts.  */;

>         else if ((TREE_CODE (newdecl) == FUNCTION_DECL

>   		&& DECL_FUNCTION_TEMPLATE_P (olddecl))

>   	       || (TREE_CODE (olddecl) == FUNCTION_DECL

> @@ -1701,7 +1711,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)

>   		      " literal operator template", newdecl);

>   	  else

>   	    return NULL_TREE;

> -	

> +

>   	  inform (olddecl_loc, "previous declaration %q#D", olddecl);

>   	  return error_mark_node;

>   	}

> diff --git a/gcc/testsuite/g++.dg/cpp1y/pr68578.C b/gcc/testsuite/g++.dg/cpp1y/pr68578.C

> index 18edd83cd7f..9b3898176f1 100644

> --- a/gcc/testsuite/g++.dg/cpp1y/pr68578.C

> +++ b/gcc/testsuite/g++.dg/cpp1y/pr68578.C

> @@ -1,4 +1,4 @@

>   // { dg-do compile { target c++14 } }

>   

> -template <typename> struct bar foo; template <> struct foo<>:  // { dg-error "class template" }

> +template <typename> struct bar foo; template <> struct foo<>:  // { dg-error "class template|redeclared" }

>   // { dg-error "-:expected" "" { target *-*-* } .+1 }

> diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ66.C b/gcc/testsuite/g++.dg/cpp1y/var-templ66.C

> new file mode 100644

> index 00000000000..65cd3d9d31b

> --- /dev/null

> +++ b/gcc/testsuite/g++.dg/cpp1y/var-templ66.C

> @@ -0,0 +1,7 @@

> +// PR c++/94553

> +// { dg-do compile { target c++14 } }

> +

> +struct C { };

> +template<typename> int C; // { dg-error "different kind of entity" }

> +template<typename> int D;

> +struct D { }; // { dg-error "different kind of entity" }

> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-redecl1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-redecl1.C

> new file mode 100644

> index 00000000000..33cd778a318

> --- /dev/null

> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-redecl1.C

> @@ -0,0 +1,7 @@

> +// PR c++/94553

> +// { dg-do compile { target c++20 } }

> +

> +struct E { };

> +template<typename> concept E = false; // { dg-error "different kind of entity" }

> +template<typename> concept F = false;

> +struct F { }; // { dg-error "different kind of entity" }

> 

> base-commit: b3d77404c060c0d65d8d4c97254995737d0fc032

>

Patch

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 3afad5ca805..45c871af741 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -1679,6 +1679,16 @@  duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
       else if (DECL_TYPE_TEMPLATE_P (olddecl)
 	       || DECL_TYPE_TEMPLATE_P (newdecl))
 	/* Class template conflicts.  */;
+      else if ((TREE_CODE (olddecl) == TEMPLATE_DECL
+		&& DECL_TEMPLATE_RESULT (olddecl)
+		&& TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)) == VAR_DECL)
+	       || (TREE_CODE (newdecl) == TEMPLATE_DECL
+		   && DECL_TEMPLATE_RESULT (newdecl)
+		   && TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == VAR_DECL))
+	/* Variable template conflicts.  */;
+      else if (concept_definition_p (olddecl)
+	       || concept_definition_p (newdecl))
+	/* Concept conflicts.  */;
       else if ((TREE_CODE (newdecl) == FUNCTION_DECL
 		&& DECL_FUNCTION_TEMPLATE_P (olddecl))
 	       || (TREE_CODE (olddecl) == FUNCTION_DECL
@@ -1701,7 +1711,7 @@  duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
 		      " literal operator template", newdecl);
 	  else
 	    return NULL_TREE;
-	  
+
 	  inform (olddecl_loc, "previous declaration %q#D", olddecl);
 	  return error_mark_node;
 	}
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr68578.C b/gcc/testsuite/g++.dg/cpp1y/pr68578.C
index 18edd83cd7f..9b3898176f1 100644
--- a/gcc/testsuite/g++.dg/cpp1y/pr68578.C
+++ b/gcc/testsuite/g++.dg/cpp1y/pr68578.C
@@ -1,4 +1,4 @@ 
 // { dg-do compile { target c++14 } }
 
-template <typename> struct bar foo; template <> struct foo<>:  // { dg-error "class template" }
+template <typename> struct bar foo; template <> struct foo<>:  // { dg-error "class template|redeclared" }
 // { dg-error "-:expected" "" { target *-*-* } .+1 }
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ66.C b/gcc/testsuite/g++.dg/cpp1y/var-templ66.C
new file mode 100644
index 00000000000..65cd3d9d31b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/var-templ66.C
@@ -0,0 +1,7 @@ 
+// PR c++/94553
+// { dg-do compile { target c++14 } }
+
+struct C { };
+template<typename> int C; // { dg-error "different kind of entity" }
+template<typename> int D;
+struct D { }; // { dg-error "different kind of entity" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-redecl1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-redecl1.C
new file mode 100644
index 00000000000..33cd778a318
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-redecl1.C
@@ -0,0 +1,7 @@ 
+// PR c++/94553
+// { dg-do compile { target c++20 } }
+
+struct E { };
+template<typename> concept E = false; // { dg-error "different kind of entity" }
+template<typename> concept F = false;
+struct F { }; // { dg-error "different kind of entity" }