re PR c++/92078 (error: 'struct std::ptr<Iter>' redeclared with different access)
authorAndrew Sutton <asutton@lock3software.com>
Tue, 19 Nov 2019 15:18:50 +0000 (15:18 +0000)
committerAndrew Sutton <asutton@gcc.gnu.org>
Tue, 19 Nov 2019 15:18:50 +0000 (15:18 +0000)
PR c++/92078

gcc/cp/
* pt.c (maybe_new_partial_specialization): Apply access to newly
created partial specializations. Update comment style.

gcc/testsuite/
* g++.dg/cpp2a/concepts-pr92078.C: New.
  * g++.dg/cpp2a/concepts-requires18.C: Update diagnostics.

From-SVN: r278450

gcc/cp/ChangeLog
gcc/cp/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp2a/concepts-pr92078.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/concepts-requires18.C

index 819de73..08b44c5 100644 (file)
@@ -1,5 +1,11 @@
 2019-11-19  Andrew Sutton  <asutton@lock3software.com>
 
+       PR c++/92078
+       * pt.c (maybe_new_partial_specialization): Apply access to newly
+       created partial specializations. Update comment style.
+
+2019-11-19  Andrew Sutton  <asutton@lock3software.com>
+
        PR c++/92403
        Suppress diagnostics substituting into a requires-expression.
        * pt.c (tsubst_copy_and_build): Perform the first substitution without
index 424098a..59f9d03 100644 (file)
@@ -848,58 +848,59 @@ check_explicit_instantiation_namespace (tree spec)
               spec, current_namespace, ns);
 }
 
-// Returns the type of a template specialization only if that
-// specialization needs to be defined. Otherwise (e.g., if the type has
-// already been defined), the function returns NULL_TREE.
+/* Returns the type of a template specialization only if that
+   specialization needs to be defined. Otherwise (e.g., if the type has
+   already been defined), the function returns NULL_TREE.  */
+
 static tree
 maybe_new_partial_specialization (tree type)
 {
-  // An implicit instantiation of an incomplete type implies
-  // the definition of a new class template.
-  //
-  //    template<typename T>
-  //      struct S;
-  //
-  //    template<typename T>
-  //      struct S<T*>;
-  //
-  // Here, S<T*> is an implicit instantiation of S whose type
-  // is incomplete.
+  /* An implicit instantiation of an incomplete type implies
+     the definition of a new class template.
+
+       template<typename T>
+         struct S;
+
+       template<typename T>
+         struct S<T*>;
+
+     Here, S<T*> is an implicit instantiation of S whose type
+     is incomplete.  */
   if (CLASSTYPE_IMPLICIT_INSTANTIATION (type) && !COMPLETE_TYPE_P (type))
     return type;
 
-  // It can also be the case that TYPE is a completed specialization.
-  // Continuing the previous example, suppose we also declare:
-  //
-  //    template<typename T>
-  //      requires Integral<T>
-  //        struct S<T*>;
-  //
-  // Here, S<T*> refers to the specialization S<T*> defined
-  // above. However, we need to differentiate definitions because
-  // we intend to define a new partial specialization. In this case,
-  // we rely on the fact that the constraints are different for
-  // this declaration than that above.
-  //
-  // Note that we also get here for injected class names and
-  // late-parsed template definitions. We must ensure that we
-  // do not create new type declarations for those cases.
+  /* It can also be the case that TYPE is a completed specialization.
+     Continuing the previous example, suppose we also declare:
+
+       template<typename T>
+         requires Integral<T>
+           struct S<T*>;
+
+     Here, S<T*> refers to the specialization S<T*> defined
+     above. However, we need to differentiate definitions because
+     we intend to define a new partial specialization. In this case,
+     we rely on the fact that the constraints are different for
+     this declaration than that above.
+
+     Note that we also get here for injected class names and
+     late-parsed template definitions. We must ensure that we
+     do not create new type declarations for those cases.  */
   if (flag_concepts && CLASSTYPE_TEMPLATE_SPECIALIZATION (type))
     {
       tree tmpl = CLASSTYPE_TI_TEMPLATE (type);
       tree args = CLASSTYPE_TI_ARGS (type);
 
-      // If there are no template parameters, this cannot be a new
-      // partial template specializtion?
+      /* If there are no template parameters, this cannot be a new
+        partial template specialization?  */
       if (!current_template_parms)
         return NULL_TREE;
 
-      // The injected-class-name is not a new partial specialization.
+      /* The injected-class-name is not a new partial specialization.  */
       if (DECL_SELF_REFERENCE_P (TYPE_NAME (type)))
        return NULL_TREE;
 
-      // If the constraints are not the same as those of the primary
-      // then, we can probably create a new specialization.
+      /* If the constraints are not the same as those of the primary
+        then, we can probably create a new specialization.  */
       tree type_constr = current_template_constraints ();
 
       if (type == TREE_TYPE (tmpl))
@@ -909,8 +910,8 @@ maybe_new_partial_specialization (tree type)
            return NULL_TREE;
        }
 
-      // Also, if there's a pre-existing specialization with matching
-      // constraints, then this also isn't new.
+      /* Also, if there's a pre-existing specialization with matching
+        constraints, then this also isn't new.  */
       tree specs = DECL_TEMPLATE_SPECIALIZATIONS (tmpl);
       while (specs)
         {
@@ -923,8 +924,8 @@ maybe_new_partial_specialization (tree type)
           specs = TREE_CHAIN (specs);
         }
 
-      // Create a new type node (and corresponding type decl)
-      // for the newly declared specialization.
+      /* Create a new type node (and corresponding type decl)
+        for the newly declared specialization.  */
       tree t = make_class_type (TREE_CODE (type));
       CLASSTYPE_DECLARED_CLASS (t) = CLASSTYPE_DECLARED_CLASS (type);
       SET_TYPE_TEMPLATE_INFO (t, build_template_info (tmpl, args));
@@ -934,10 +935,12 @@ maybe_new_partial_specialization (tree type)
         equivalent.  So keep TYPE_CANONICAL the same.  */
       TYPE_CANONICAL (t) = TYPE_CANONICAL (type);
 
-      // Build the corresponding type decl.
+      /* Build the corresponding type decl.  */
       tree d = create_implicit_typedef (DECL_NAME (tmpl), t);
       DECL_CONTEXT (d) = TYPE_CONTEXT (t);
       DECL_SOURCE_LOCATION (d) = input_location;
+      TREE_PRIVATE (d) = (current_access_specifier == access_private_node);
+      TREE_PROTECTED (d) = (current_access_specifier == access_protected_node);
 
       return t;
     }
index 878bc02..edbf126 100644 (file)
@@ -1,3 +1,9 @@
+2019-11-19  Andrew Sutton  <asutton@lock3software.com>
+
+       PR c++/92078
+       * g++.dg/cpp2a/concepts-pr92078.C: New.
+       * g++.dg/cpp2a/concepts-requires18.C: Update diagnostics.
+
 2019-11-19  Andrew Stubbs  <ams@codesourcery.com>
 
        * gcc.dg/tree-ssa/loop-1.c: Change amdgcn assembler scan.
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr92078.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr92078.C
new file mode 100644 (file)
index 0000000..9bfb896
--- /dev/null
@@ -0,0 +1,20 @@
+// { dg-do compile { target c++2a } }
+
+template<typename I>
+struct iterator_traits
+{
+private:
+  template<typename Iter>
+  struct ptr
+  { };
+
+  template<typename J>
+    requires requires { typename J::X; }
+  struct ptr<J>
+  { };
+
+  template<typename J>
+    requires (!requires { typename J::X; } && requires { typename J::Y; })
+  struct ptr<J>
+  { };
+};
index 9d9d0d9..c76b12c 100644 (file)
@@ -44,13 +44,25 @@ struct data
   template<typename U>
   constexpr bool test()
   {
-    if constexpr (requires { requires subst<U&>; }) // { dg-error "forming reference" }
+    if constexpr (requires { requires subst<U&>; })
       return true;
     else
       return false;
   }
 };
 
+template<typename T>
+constexpr bool check_for_resize(T &v, unsigned const n)
+{
+  if constexpr (requires { v.resize(n); })
+    return true;
+  else
+    return false;
+}
+
+struct array { };
+struct vector { void resize(int n); };
+
 void test()
 {
   f1<int>();
@@ -74,4 +86,9 @@ void test()
   data<int> t;
   static_assert(t.test<int>());
   static_assert(t.test<void>()); // { dg-error "static assertion failed" }
+
+  vector v;
+  static_assert(check_for_resize(v, 10));
+  array a;
+  static_assert(!check_for_resize(a, 10));
 }