diff mbox

C++ PATCH for concept checking in non-dependent expressions

Message ID 9f385187-28e3-981f-4bf1-76d7128f792e@redhat.com
State New
Headers show

Commit Message

Jason Merrill June 21, 2016, 6:15 p.m. UTC
Concept code also needs some updates to accommodate my GCC 7 fix for 
10200.  First, and not limited to concepts, we need to treat a member 
template as dependent if its signature depends on template parameters of 
its enclosing class (which, more importantly, are template parameters of 
the scope where the member template is named).  Second, 
constraints_satisfied_p needs the same kind of change that I made to 
instantiate_decl and fn_type_unification to handle non-dependent calls 
within a template.  The testcase tests both these changes.

Tested x86_64-pc-linux-gnu, applying to trunk.
diff mbox

Patch

commit 44d09c91bac2a200149e30c1d1bbc13042c6a723
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Jun 20 11:22:49 2016 +0300

    	Fix type_dependent_expression_p of member templates.
    
    	* pt.c (template_parm_outer_level, uses_outer_template_parms): New.
    	(type_dependent_expression_p): Use uses_outer_template_parms.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 11b5d82..c5f65a7 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -5064,6 +5064,24 @@  template_parm_this_level_p (tree t, void* data)
   return level == this_level;
 }
 
+/* Worker for uses_outer_template_parms, called via for_each_template_parm.
+   DATA is really an int, indicating the innermost outer level of parameters.
+   If T is a template parameter of that level or further out, return
+   nonzero.  */
+
+static int
+template_parm_outer_level (tree t, void *data)
+{
+  int this_level = *(int *)data;
+  int level;
+
+  if (TREE_CODE (t) == TEMPLATE_PARM_INDEX)
+    level = TEMPLATE_PARM_LEVEL (t);
+  else
+    level = TEMPLATE_TYPE_LEVEL (t);
+  return level <= this_level;
+}
+
 /* Creates a TEMPLATE_DECL for the indicated DECL using the template
    parameters given by current_template_args, or reuses a
    previously existing one, if appropriate.  Returns the DECL, or an
@@ -9032,6 +9050,33 @@  uses_template_parms_level (tree t, int level)
 				 /*include_nondeduced_p=*/true);
 }
 
+/* Returns true if the signature of DECL depends on any template parameter from
+   its enclosing class.  */
+
+bool
+uses_outer_template_parms (tree decl)
+{
+  int depth = template_class_depth (CP_DECL_CONTEXT (decl));
+  if (depth == 0)
+    return false;
+  if (for_each_template_parm (TREE_TYPE (decl), template_parm_outer_level,
+			      &depth, NULL, /*include_nondeduced_p=*/true))
+    return true;
+  if (PRIMARY_TEMPLATE_P (decl)
+      && for_each_template_parm (INNERMOST_TEMPLATE_PARMS
+				 (DECL_TEMPLATE_PARMS (decl)),
+				 template_parm_outer_level,
+				 &depth, NULL, /*include_nondeduced_p=*/true))
+    return true;
+  tree ci = get_constraints (decl);
+  if (ci)
+    ci = CI_NORMALIZED_CONSTRAINTS (ci);
+  if (ci && for_each_template_parm (ci, template_parm_outer_level,
+				    &depth, NULL, /*nondeduced*/true))
+    return true;
+  return false;
+}
+
 /* Returns TRUE iff INST is an instantiation we don't need to do in an
    ill-formed translation unit, i.e. a variable or function that isn't
    usable in a constant expression.  */
@@ -23008,7 +23053,7 @@  type_dependent_expression_p (tree expression)
 
   if (TREE_CODE (expression) == TEMPLATE_DECL
       && !DECL_TEMPLATE_TEMPLATE_PARM_P (expression))
-    return false;
+    return uses_outer_template_parms (expression);
 
   if (TREE_CODE (expression) == STMT_EXPR)
     expression = stmt_expr_value_expr (expression);

commit 2f9c0996e3c50d7c84c34c3353ac70a7c10c0141
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Jun 20 11:24:10 2016 +0300

    	Fix constraint satisfaction in uninstantiated template.
    
    	* constraint.cc (constraints_satisfied_p): Keep as many levels of
    	args as our template has levels of parms.

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 5e42fa9..af7a593 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -2122,8 +2122,10 @@  constraints_satisfied_p (tree decl)
   tree args = NULL_TREE;
   if (tree ti = DECL_TEMPLATE_INFO (decl))
     {
-      ci = get_constraints (TI_TEMPLATE (ti));
-      args = INNERMOST_TEMPLATE_ARGS (TI_ARGS (ti));
+      tree tmpl = TI_TEMPLATE (ti);
+      ci = get_constraints (tmpl);
+      int depth = TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl));
+      args = get_innermost_template_args (TI_ARGS (ti), depth);
     }
   else
     {
diff --git a/gcc/testsuite/g++.dg/concepts/memtmpl1.C b/gcc/testsuite/g++.dg/concepts/memtmpl1.C
new file mode 100644
index 0000000..6f3d5a3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/concepts/memtmpl1.C
@@ -0,0 +1,15 @@ 
+// { dg-options "-std=c++1z -fconcepts" }
+
+template <class T>
+struct A {
+  template <class U>
+  requires sizeof(T) == 1
+    static void f(U);
+  template <class U>
+  requires sizeof(T) == 2
+    static void f(U);
+  void g()
+  {
+    f(42);
+  }
+};