c++: constraints and explicit instantiation [PR96164]
authorPatrick Palka <ppalka@redhat.com>
Thu, 30 Jul 2020 02:06:33 +0000 (22:06 -0400)
committerPatrick Palka <ppalka@redhat.com>
Thu, 30 Jul 2020 02:06:33 +0000 (22:06 -0400)
When considering to instantiate a member of a class template as part of
an explicit instantiation of the class template, we need to first check
the member's constraints before proceeding with the instantiation of the
member.

gcc/cp/ChangeLog:

PR c++/96164
* constraint.cc (constraints_satisfied_p): Return true if
!flags_concepts.
* pt.c (do_type_instantiation): Update a paragraph taken from
[temp.explicit] to reflect the latest specification.  Don't
instantiate a member with unsatisfied constraints.

gcc/testsuite/ChangeLog:

PR c++/96164
* g++.dg/cpp2a/concepts-explicit-inst5.C: New test.

gcc/cp/constraint.cc
gcc/cp/pt.c
gcc/testsuite/g++.dg/cpp2a/concepts-explicit-inst5.C [new file with mode: 0644]

index d0da2300ba99e2825db59fd5acbdc43bf6aa9cf3..e4aace596e7c1919ee45f629671bdf527b56a5bb 100644 (file)
@@ -2864,6 +2864,9 @@ constraint_satisfaction_value (tree t, tree args, tsubst_flags_t complain)
 bool
 constraints_satisfied_p (tree t)
 {
+  if (!flag_concepts)
+    return true;
+
   return constraint_satisfaction_value (t, tf_none) == boolean_true_node;
 }
 
@@ -2873,6 +2876,9 @@ constraints_satisfied_p (tree t)
 bool
 constraints_satisfied_p (tree t, tree args)
 {
+  if (!flag_concepts)
+    return true;
+
   return constraint_satisfaction_value (t, args, tf_none) == boolean_true_node;
 }
 
index 6a42cf93dccb4518d50020465d20bfc035505951..9b4e6ce7d89d9d13188f473919a7437f9ecbf04d 100644 (file)
@@ -24928,23 +24928,22 @@ do_type_instantiation (tree t, tree storage, tsubst_flags_t complain)
 
         [temp.explicit]
 
-        The explicit instantiation of a class template specialization
-        implies the instantiation of all of its members not
-        previously explicitly specialized in the translation unit
-        containing the explicit instantiation.
-
-     Of course, we can't instantiate member template classes, since we
-     don't have any arguments for them.  Note that the standard is
-     unclear on whether the instantiation of the members are
-     *explicit* instantiations or not.  However, the most natural
-     interpretation is that it should be an explicit
-     instantiation.  */
+        An explicit instantiation that names a class template
+        specialization is also an explicit instantiation of the same
+        kind (declaration or definition) of each of its members (not
+        including members inherited from base classes and members
+        that are templates) that has not been previously explicitly
+        specialized in the translation unit containing the explicit
+        instantiation, provided that the associated constraints, if
+        any, of that member are satisfied by the template arguments
+        of the explicit instantiation.  */
   for (tree fld = TYPE_FIELDS (t); fld; fld = DECL_CHAIN (fld))
     if ((VAR_P (fld)
         || (TREE_CODE (fld) == FUNCTION_DECL
             && !static_p
             && user_provided_p (fld)))
-       && DECL_TEMPLATE_INSTANTIATION (fld))
+       && DECL_TEMPLATE_INSTANTIATION (fld)
+       && constraints_satisfied_p (fld))
       {
        mark_decl_instantiated (fld, extern_p);
        if (! extern_p)
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-explicit-inst5.C b/gcc/testsuite/g++.dg/cpp2a/concepts-explicit-inst5.C
new file mode 100644 (file)
index 0000000..05959a8
--- /dev/null
@@ -0,0 +1,14 @@
+// PR c++/96164
+// { dg-do compile { target concepts } }
+
+template <int N>
+struct A {
+    void f() requires (N == 3) { static_assert(N == 3); }
+};
+template struct A<2>;
+
+template <int N>
+struct B {
+    void f() requires (N == 2) { static_assert(N == 3); } // { dg-error "assert" }
+};
+template struct B<2>;