c++: Check uniqueness of concepts/variable templates [PR94553]
authorMarek Polacek <polacek@redhat.com>
Fri, 26 Jun 2020 16:40:59 +0000 (12:40 -0400)
committerMarek Polacek <polacek@redhat.com>
Mon, 29 Jun 2020 15:01:58 +0000 (11:01 -0400)
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.

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
gcc/testsuite/g++.dg/cpp1y/pr68578.C
gcc/testsuite/g++.dg/cpp1y/var-templ66.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/concepts-redecl1.C [new file with mode: 0644]

index 3afad5ca80505971e58ae130c9618965c563ad2d..45c871af7415e86d722a723be72d47117f15c309 100644 (file)
@@ -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;
        }
index 18edd83cd7f3c83a7e6f3fdb4c6249f3f0ff3adf..9b3898176f1e2c9fbb7e8e043d35817dfba2c2b2 100644 (file)
@@ -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 (file)
index 0000000..65cd3d9
--- /dev/null
@@ -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 (file)
index 0000000..33cd778
--- /dev/null
@@ -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" }