c++: Rewrite members for all deduction guides. [PR96199]
authorJason Merrill <jason@redhat.com>
Fri, 14 Aug 2020 22:01:27 +0000 (18:01 -0400)
committerJason Merrill <jason@redhat.com>
Tue, 18 Aug 2020 20:20:09 +0000 (16:20 -0400)
After the last patch, it occurred to me that we could run into the
specialization issue with non-alias deduction guides as well, so this patch
extends the rewriting to C++17 mode.

Doing this revealed that we weren't properly pushing into class scope for
normalization.

gcc/cp/ChangeLog:

PR c++/96199
* pt.c (tsubst_aggr_type): Rewrite in C++17, too.
(maybe_dependent_member_ref): Likewise.
(build_deduction_guide): Re-substitute template parms.
* cp-tree.h (struct push_nested_class_guard): New.
* constraint.cc (get_normalized_constraints_from_decl): Use it.

gcc/testsuite/ChangeLog:

PR c++/96199
* g++.dg/cpp1z/class-deduction-spec1.C: New test.

gcc/cp/constraint.cc
gcc/cp/cp-tree.h
gcc/cp/pt.c
gcc/testsuite/g++.dg/cpp1z/class-deduction-spec1.C [new file with mode: 0644]

index e4aace596e7c1919ee45f629671bdf527b56a5bb..48d52ec5b7acb0265100ff63f0b9964e20b81efb 100644 (file)
@@ -840,6 +840,8 @@ get_normalized_constraints_from_decl (tree d, bool diag = false)
     if (tree *p = hash_map_safe_get (normalized_map, tmpl))
       return *p;
 
+  push_nested_class_guard pncs (DECL_CONTEXT (d));
+
   tree args = generic_targs_for (tmpl);
   tree ci = get_constraints (decl);
   tree norm = get_normalized_constraints_from_info (ci, args, tmpl, diag);
index 047585740191a9ab62d54f300918b69e480c6978..5ba82ee60db35c860a2ebd019d112bda4c7121b6 100644 (file)
@@ -8137,6 +8137,24 @@ is_constrained_auto (const_tree t)
   return is_auto (t) && PLACEHOLDER_TYPE_CONSTRAINTS (t);
 }
 
+/* RAII class to push/pop class scope T; if T is not a class, do nothing.  */
+
+struct push_nested_class_guard
+{
+  bool push;
+  push_nested_class_guard (tree t)
+    : push (t && CLASS_TYPE_P (t))
+  {
+    if (push)
+      push_nested_class (t);
+  }
+  ~push_nested_class_guard ()
+  {
+    if (push)
+      pop_nested_class ();
+  }
+};
+
 #if CHECKING_P
 namespace selftest {
   extern void run_cp_tests (void);
index 585d944542b6108f6424170ffd4821839e90b177..8ad91b37297a256ffff34ad344be44744725eb38 100644 (file)
@@ -13391,7 +13391,7 @@ tsubst_aggr_type (tree t,
                                         complain, in_decl);
          if (argvec == error_mark_node)
            r = error_mark_node;
-         else if (cxx_dialect >= cxx20 && dependent_scope_p (context))
+         else if (cxx_dialect >= cxx17 && dependent_scope_p (context))
            {
              /* See maybe_dependent_member_ref.  */
              tree name = TYPE_IDENTIFIER (t);
@@ -16328,14 +16328,13 @@ tsubst_init (tree init, tree decl, tree args,
    we are trying to refer to that member in a partial instantiation of C,
    return a SCOPE_REF; otherwise, return NULL_TREE.
 
-   This can happen when forming a C++20 alias template deduction guide, as in
-   PR96199.  */
+   This can happen when forming a C++17 deduction guide, as in PR96199.  */
 
 static tree
 maybe_dependent_member_ref (tree t, tree args, tsubst_flags_t complain,
                            tree in_decl)
 {
-  if (cxx_dialect < cxx20)
+  if (cxx_dialect < cxx17)
     return NULL_TREE;
 
   tree ctx = context_for_name_lookup (t);
@@ -28370,6 +28369,16 @@ build_deduction_guide (tree type, tree ctor, tree outer_args, tsubst_flags_t com
          fargs = tsubst (fargs, tsubst_args, complain, ctor);
          current_template_parms = save_parms;
        }
+      else
+       {
+         /* Substitute in the same arguments to rewrite class members into
+            references to members of an unknown specialization.  */
+         cp_evaluated ev;
+         fparms = tsubst_arg_types (fparms, targs, NULL_TREE, complain, ctor);
+         fargs = tsubst (fargs, targs, complain, ctor);
+         if (ci)
+           ci = tsubst_constraint_info (ci, targs, complain, ctor);
+       }
 
       --processing_template_decl;
       if (!ok)
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction-spec1.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction-spec1.C
new file mode 100644 (file)
index 0000000..fcdf746
--- /dev/null
@@ -0,0 +1,38 @@
+// PR c++/96199
+// { dg-do compile { target c++17 } }
+
+template<int> struct A1 { };
+template<int&> struct A2 { };
+template<class> struct A3 { };
+
+int i;
+template<typename V> struct B {
+  enum E { X };
+  B(A1<X>, V) { }
+
+  constexpr static V& ir = i;
+  B(A2<ir>, V) { }
+
+  B(A3<E>, V) { }
+};
+
+// template<class T> B(A1<B<T>::X>,T) -> B<T>;
+// template<class T> B(A2<B<T>::ir>,T) -> B<T>;
+// template<class T> B(A3<typename B<T>::E>,T) -> B<T>;
+
+int j;
+template <> struct B<int> {
+  using V = int;
+
+  enum E { X = 1 };
+  B(A1<X>, V) { }
+
+  constexpr static V& ir = j;
+  B(A2<ir>, V) { }
+
+  B(A3<E>, V) { }
+};
+
+B u1 { A1<1>(), 42 };
+B u2 { A2<j>(), 42 };
+B u3 { A3<B<int>::E>(), 42 };