public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r12-7631] c++: return-type-req in constraint using only outer tparms [PR104527]
@ 2022-03-12 20:02 Patrick Palka
  0 siblings, 0 replies; only message in thread
From: Patrick Palka @ 2022-03-12 20:02 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:9413bb55185b9e88d84e91d5145d59f9f83b884a

commit r12-7631-g9413bb55185b9e88d84e91d5145d59f9f83b884a
Author: Patrick Palka <ppalka@redhat.com>
Date:   Sat Mar 12 15:00:40 2022 -0500

    c++: return-type-req in constraint using only outer tparms [PR104527]
    
    Here the template context for the atomic constraint has two levels of
    template parameters, but since it depends only on the innermost parameter
    T we use a single-level argument vector (built by get_mapped_args) during
    substitution into the atom.  We eventually pass this vector to
    do_auto_deduction as part of checking the return-type-requirement within
    the atom, but do_auto_deduction expects outer_targs to be a full set of
    arguments for sake of satisfaction.
    
    This patch fixes this by making get_mapped_args always return an
    argument vector whose depth corresponds to the template depth of the
    context in which the atomic constraint expression was written, instead
    of the highest parameter level that the expression happens to use.
    
            PR c++/104527
    
    gcc/cp/ChangeLog:
    
            * constraint.cc (normalize_atom): Set
            ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P appropriately.
            (get_mapped_args):  Make static, adjust parameters.  Always
            return a vector whose depth corresponds to the template depth of
            the context of the atomic constraint expression.  Micro-optimize
            by passing false as exact to safe_grow_cleared and by collapsing
            a multi-level depth-one argument vector.
            (satisfy_atom): Adjust call to get_mapped_args and
            diagnose_atomic_constraint.
            (diagnose_atomic_constraint): Replace map parameter with an args
            parameter.
            * cp-tree.h (ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P): Define.
            (get_mapped_args): Remove declaration.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/cpp2a/concepts-return-req4.C: New test.

Diff:
---
 gcc/cp/constraint.cc                              | 70 +++++++++++++++--------
 gcc/cp/cp-tree.h                                  |  7 ++-
 gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C | 24 ++++++++
 3 files changed, 75 insertions(+), 26 deletions(-)

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 12db7e5cf14..e14578b1721 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -764,6 +764,15 @@ normalize_atom (tree t, tree args, norm_info info)
   tree ci = build_tree_list (t, info.context);
 
   tree atom = build1 (ATOMIC_CONSTR, ci, map);
+
+  /* Remember whether the expression of this atomic constraint belongs to
+     a concept definition by inspecting in_decl, which should always be set
+     in this case either by norm_info::update_context (when recursing into a
+     concept-id during normalization) or by normalize_concept_definition
+     (when starting out with a concept-id).  */
+  if (info.in_decl && concept_definition_p (info.in_decl))
+    ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (atom) = true;
+
   if (!info.generate_diagnostics ())
     {
       /* Cache the ATOMIC_CONSTRs that we return, so that sat_hasher::equal
@@ -2826,33 +2835,37 @@ satisfaction_value (tree t)
     return boolean_true_node;
 }
 
-/* Build a new template argument list with template arguments corresponding
-   to the parameters used in an atomic constraint.  */
+/* Build a new template argument vector corresponding to the parameter
+   mapping of the atomic constraint T, using arguments from ARGS.  */
 
-tree
-get_mapped_args (tree map)
+static tree
+get_mapped_args (tree t, tree args)
 {
+  tree map = ATOMIC_CONSTR_MAP (t);
+
   /* No map, no arguments.  */
   if (!map)
     return NULL_TREE;
 
-  /* Find the mapped parameter with the highest level.  */
-  int count = 0;
-  for (tree p = map; p; p = TREE_CHAIN (p))
-    {
-      int level;
-      int index;
-      template_parm_level_and_index (TREE_VALUE (p), &level, &index);
-      if (level > count)
-        count = level;
-    }
+  /* Determine the depth of the resulting argument vector.  */
+  int depth;
+  if (ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (t))
+    /* The expression of this atomic constraint comes from a concept definition,
+       whose template depth is always one, so the resulting argument vector
+       will also have depth one.  */
+    depth = 1;
+  else
+    /* Otherwise, the expression of this atomic constraint comes from
+       the context of the constrained entity, whose template depth is that
+       of ARGS.  */
+    depth = TMPL_ARGS_DEPTH (args);
 
   /* Place each argument at its corresponding position in the argument
      list. Note that the list will be sparse (not all arguments supplied),
      but instantiation is guaranteed to only use the parameters in the
      mapping, so null arguments would never be used.  */
-  auto_vec< vec<tree> > lists (count);
-  lists.quick_grow_cleared (count);
+  auto_vec< vec<tree> > lists (depth);
+  lists.quick_grow_cleared (depth);
   for (tree p = map; p; p = TREE_CHAIN (p))
     {
       int level;
@@ -2862,12 +2875,12 @@ get_mapped_args (tree map)
       /* Insert the argument into its corresponding position.  */
       vec<tree> &list = lists[level - 1];
       if (index >= (int)list.length ())
-	list.safe_grow_cleared (index + 1, true);
+	list.safe_grow_cleared (index + 1, /*exact=*/false);
       list[index] = TREE_PURPOSE (p);
     }
 
   /* Build the new argument list.  */
-  tree args = make_tree_vec (lists.length ());
+  args = make_tree_vec (lists.length ());
   for (unsigned i = 0; i != lists.length (); ++i)
     {
       vec<tree> &list = lists[i];
@@ -2879,6 +2892,15 @@ get_mapped_args (tree map)
     }
   SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (args, 0);
 
+  if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args)
+      && TMPL_ARGS_DEPTH (args) == 1)
+    {
+      /* Get rid of the redundant outer TREE_VEC.  */
+      tree level = TMPL_ARGS_LEVEL (args, 1);
+      ggc_free (args);
+      args = level;
+    }
+
   return args;
 }
 
@@ -2933,7 +2955,7 @@ satisfy_atom (tree t, tree args, sat_info info)
     }
 
   /* Rebuild the argument vector from the parameter mapping.  */
-  args = get_mapped_args (map);
+  args = get_mapped_args (t, args);
 
   /* Apply the parameter mapping (i.e., just substitute).  */
   tree expr = ATOMIC_CONSTR_EXPR (t);
@@ -2955,7 +2977,7 @@ satisfy_atom (tree t, tree args, sat_info info)
   if (!same_type_p (TREE_TYPE (result), boolean_type_node))
     {
       if (info.noisy ())
-	diagnose_atomic_constraint (t, map, result, info);
+	diagnose_atomic_constraint (t, args, result, info);
       return cache.save (inst_cache.save (error_mark_node));
     }
 
@@ -2974,7 +2996,7 @@ satisfy_atom (tree t, tree args, sat_info info)
     }
   result = satisfaction_value (result);
   if (result == boolean_false_node && info.diagnose_unsatisfaction_p ())
-    diagnose_atomic_constraint (t, map, result, info);
+    diagnose_atomic_constraint (t, args, result, info);
 
   return cache.save (inst_cache.save (result));
 }
@@ -3642,11 +3664,10 @@ diagnose_trait_expr (tree expr, tree args)
     }
 }
 
-/* Diagnose a substitution failure in the atomic constraint T when applied
-   with the instantiated parameter mapping MAP.  */
+/* Diagnose a substitution failure in the atomic constraint T using ARGS.  */
 
 static void
-diagnose_atomic_constraint (tree t, tree map, tree result, sat_info info)
+diagnose_atomic_constraint (tree t, tree args, tree result, sat_info info)
 {
   /* If the constraint is already ill-formed, we've previously diagnosed
      the reason. We should still say why the constraints aren't satisfied.  */
@@ -3667,7 +3688,6 @@ diagnose_atomic_constraint (tree t, tree map, tree result, sat_info info)
   /* Generate better diagnostics for certain kinds of expressions.  */
   tree expr = ATOMIC_CONSTR_EXPR (t);
   STRIP_ANY_LOCATION_WRAPPER (expr);
-  tree args = get_mapped_args (map);
   switch (TREE_CODE (expr))
     {
     case TRAIT_EXPR:
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index b71bce1ab97..02054142cb1 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -466,6 +466,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
       IMPLICIT_CONV_EXPR_NONTYPE_ARG (in IMPLICIT_CONV_EXPR)
       BASELINK_FUNCTIONS_MAYBE_INCOMPLETE_P (in BASELINK)
       BIND_EXPR_VEC_DTOR (in BIND_EXPR)
+      ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (in ATOMIC_CONSTR)
    2: IDENTIFIER_KIND_BIT_2 (in IDENTIFIER_NODE)
       ICS_THIS_FLAG (in _CONV)
       DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL)
@@ -1679,6 +1680,11 @@ check_constraint_info (tree t)
 #define ATOMIC_CONSTR_MAP_INSTANTIATED_P(NODE) \
   TREE_LANG_FLAG_0 (ATOMIC_CONSTR_CHECK (NODE))
 
+/* Whether the expression for this atomic constraint belongs to a
+   concept definition.  */
+#define ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P(NODE) \
+  TREE_LANG_FLAG_1 (ATOMIC_CONSTR_CHECK (NODE))
+
 /* The expression of an atomic constraint. */
 #define ATOMIC_CONSTR_EXPR(NODE) \
   CONSTR_EXPR (ATOMIC_CONSTR_CHECK (NODE))
@@ -8315,7 +8321,6 @@ extern tree evaluate_requires_expr		(tree);
 extern tree tsubst_constraint                   (tree, tree, tsubst_flags_t, tree);
 extern tree tsubst_constraint_info              (tree, tree, tsubst_flags_t, tree);
 extern tree tsubst_parameter_mapping		(tree, tree, tsubst_flags_t, tree);
-extern tree get_mapped_args			(tree);
 
 struct processing_constraint_expression_sentinel
 {
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C b/gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C
new file mode 100644
index 00000000000..471946bc8eb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-return-req4.C
@@ -0,0 +1,24 @@
+// PR c++/104527
+// { dg-do compile { target c++20 } }
+
+template<class T, class U>
+concept is_same = __is_same(T, U);
+
+template<class T>
+struct A {
+  template<class...>
+    requires requires { { 0 } -> is_same<T>; }
+  struct B {};
+
+  template<class...>
+    requires requires { { 1 } -> is_same<T>; }
+  static void f();
+};
+
+A<int>::B<> a1;
+A<bool>::B<> a2; // { dg-error "constraint" }
+
+int main() {
+  A<int>::f();
+  A<bool>::f(); // { dg-error "no match" }
+}


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-03-12 20:02 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-12 20:02 [gcc r12-7631] c++: return-type-req in constraint using only outer tparms [PR104527] Patrick Palka

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).