diff mbox

C++ PATCH for c++/70634 (ICE with self-referential initializer)

Message ID 570E5F6A.1050601@redhat.com
State New
Headers show

Commit Message

Jason Merrill April 13, 2016, 3:02 p.m. UTC
The compiler was getting into infinite recursion here because when 
looking at whether 'i>0' was value-dependent, we looked at the 
initializer for i, which contains sizeof(i), and we asked whether i is 
value-dependent again.

The bug is that we shouldn't care whether the operand of sizeof is 
value-dependent; this patch splits up the instantiation-dependence 
predicate for evaluated and unevaluated expressions.  I also needed to 
swap the order of checking potential_constant_expression and 
instantiation_dependent_expression_p, so I factored out all the places 
that check those two into a new function that tests both.

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

Patch

commit 0897b3e9b5be7fc3adbe96d871876fdb8452d2a9
Author: Jason Merrill <jason@redhat.com>
Date:   Tue Apr 12 23:41:04 2016 -0400

    	PR c++/70634
    
    	* pt.c (instantiation_dependent_uneval_expression_p): Split out
    	from instantiation_dependent_expression_p.
    	(value_dependent_expression_p): Use it for unevaluated operands.
    	(instantiation_dependent_r): Don't check value-dependence.
    	(instantiation_dependent_expression_p): Check
    	value-dependence of the expression as a whole.
    	* cp-tree.h: Declare instantiation_dependent_uneval_expression_p.
    	* semantics.c (finish_decltype_type): Use it.

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index ecf2a5d..a3cd834 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6127,6 +6127,7 @@  extern bool any_type_dependent_elements_p       (const_tree);
 extern bool type_dependent_expression_p_push	(tree);
 extern bool value_dependent_expression_p	(tree);
 extern bool instantiation_dependent_expression_p (tree);
+extern bool instantiation_dependent_uneval_expression_p (tree);
 extern bool any_value_dependent_elements_p      (const_tree);
 extern bool dependent_omp_for_p			(tree, tree, tree, tree);
 extern tree resolve_typename_type		(tree, bool);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 2871f33..b75ac24 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -22720,7 +22720,7 @@  value_dependent_expression_p (tree expression)
         return true;
       else if (TYPE_P (expression))
 	return dependent_type_p (expression);
-      return instantiation_dependent_expression_p (expression);
+      return instantiation_dependent_uneval_expression_p (expression);
 
     case AT_ENCODE_EXPR:
       /* An 'encode' expression is value-dependent if the operand is
@@ -22730,7 +22730,7 @@  value_dependent_expression_p (tree expression)
 
     case NOEXCEPT_EXPR:
       expression = TREE_OPERAND (expression, 0);
-      return instantiation_dependent_expression_p (expression);
+      return instantiation_dependent_uneval_expression_p (expression);
 
     case SCOPE_REF:
       /* All instantiation-dependent expressions should also be considered
@@ -23101,13 +23101,6 @@  instantiation_dependent_r (tree *tp, int *walk_subtrees,
     case TREE_VEC:
       return NULL_TREE;
 
-    case VAR_DECL:
-    case CONST_DECL:
-      /* A constant with a dependent initializer is dependent.  */
-      if (value_dependent_expression_p (*tp))
-	return *tp;
-      break;
-
     case TEMPLATE_PARM_INDEX:
       return *tp;
 
@@ -23133,12 +23126,6 @@  instantiation_dependent_r (tree *tp, int *walk_subtrees,
 	break;
       }
 
-    case TRAIT_EXPR:
-      if (value_dependent_expression_p (*tp))
-	return *tp;
-      *walk_subtrees = false;
-      return NULL_TREE;
-
     case COMPONENT_REF:
       if (identifier_p (TREE_OPERAND (*tp, 1)))
 	/* In a template, finish_class_member_access_expr creates a
@@ -23189,10 +23176,15 @@  instantiation_dependent_r (tree *tp, int *walk_subtrees,
 
    "An expression is instantiation-dependent if it is type-dependent
    or value-dependent, or it has a subexpression that is type-dependent
-   or value-dependent."  */
+   or value-dependent."
+
+   Except don't actually check value-dependence for unevaluated expressions,
+   because in sizeof(i) we don't care about the value of i.  Checking
+   type-dependence will in turn check value-dependence of array bounds/template
+   arguments as needed.  */
 
 bool
-instantiation_dependent_expression_p (tree expression)
+instantiation_dependent_uneval_expression_p (tree expression)
 {
   tree result;
 
@@ -23207,6 +23199,15 @@  instantiation_dependent_expression_p (tree expression)
   return result != NULL_TREE;
 }
 
+/* As above, but also check value-dependence of the expression as a whole.  */
+
+bool
+instantiation_dependent_expression_p (tree expression)
+{
+  return (instantiation_dependent_uneval_expression_p (expression)
+	  || value_dependent_expression_p (expression));
+}
+
 /* Like type_dependent_expression_p, but it also works while not processing
    a template definition, i.e. during substitution or mangling.  */
 
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 1574e60..0487adf 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -8740,7 +8740,7 @@  finish_decltype_type (tree expr, bool id_expression_or_member_access_p,
   /* Depending on the resolution of DR 1172, we may later need to distinguish
      instantiation-dependent but not type-dependent expressions so that, say,
      A<decltype(sizeof(T))>::U doesn't require 'typename'.  */
-  if (instantiation_dependent_expression_p (expr))
+  if (instantiation_dependent_uneval_expression_p (expr))
     {
       type = cxx_make_type (DECLTYPE_TYPE);
       DECLTYPE_TYPE_EXPR (type) = expr;
diff --git a/gcc/testsuite/g++.dg/template/dependent-expr10.C b/gcc/testsuite/g++.dg/template/dependent-expr10.C
new file mode 100644
index 0000000..94d66fc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/dependent-expr10.C
@@ -0,0 +1,8 @@ 
+// PR c++/70634
+
+template < typename T >
+bool foo ()
+{
+  const int i = sizeof (i) > 1 ? sizeof (T) : 0;
+  return i > 0;
+}

commit 48c455ec050dd88a6f2fc696dfd006716e6a0787
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Apr 13 08:44:04 2016 -0400

    	* constexpr.c (potential_nondependent_constant_expression): New.
    	(potential_nondependent_static_init_expression): New.
    	(maybe_constant_value_1, fold_non_dependent_expr)
    	(maybe_constant_init): Use them.
    	* pt.c (instantiate_non_dependent_expr_sfinae)
    	(instantiate_non_dependent_or_null, convert_nontype_argument): Use
    	them.
    	* cp-tree.h: Declare them.

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 13f385b..37cc336 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -4315,10 +4315,7 @@  maybe_constant_value_1 (tree t, tree decl)
 {
   tree r;
 
-  if (instantiation_dependent_expression_p (t)
-      || type_unknown_p (t)
-      || BRACE_ENCLOSED_INITIALIZER_P (t)
-      || !potential_constant_expression (t))
+  if (!potential_nondependent_constant_expression (t))
     {
       if (TREE_OVERFLOW_P (t))
 	{
@@ -4397,8 +4394,7 @@  fold_non_dependent_expr (tree t)
      as two declarations of the same function, for example.  */
   if (processing_template_decl)
     {
-      if (!instantiation_dependent_expression_p (t)
-	  && potential_constant_expression (t))
+      if (potential_nondependent_constant_expression (t))
 	{
 	  processing_template_decl_sentinel s;
 	  t = instantiate_non_dependent_expr_internal (t, tf_none);
@@ -4449,10 +4445,7 @@  maybe_constant_init (tree t, tree decl)
     t = TREE_OPERAND (t, 0);
   if (TREE_CODE (t) == INIT_EXPR)
     t = TREE_OPERAND (t, 1);
-  if (instantiation_dependent_expression_p (t)
-      || type_unknown_p (t)
-      || BRACE_ENCLOSED_INITIALIZER_P (t)
-      || !potential_static_init_expression (t))
+  if (!potential_nondependent_static_init_expression (t))
     /* Don't try to evaluate it.  */;
   else
     t = cxx_eval_outermost_constant_expr (t, true, false, decl);
@@ -5203,4 +5196,29 @@  require_potential_rvalue_constant_expression (tree t)
   return potential_constant_expression_1 (t, true, true, tf_warning_or_error);
 }
 
+/* Returns true if T is a potential constant expression that is not
+   instantiation-dependent, and therefore a candidate for constant folding even
+   in a template.  */
+
+bool
+potential_nondependent_constant_expression (tree t)
+{
+  return (!type_unknown_p (t)
+	  && !BRACE_ENCLOSED_INITIALIZER_P (t)
+	  && potential_constant_expression (t)
+	  && !instantiation_dependent_expression_p (t));
+}
+
+/* Returns true if T is a potential static initializer expression that is not
+   instantiation-dependent.  */
+
+bool
+potential_nondependent_static_init_expression (tree t)
+{
+  return (!type_unknown_p (t)
+	  && !BRACE_ENCLOSED_INITIALIZER_P (t)
+	  && potential_static_init_expression (t)
+	  && !instantiation_dependent_expression_p (t));
+}
+
 #include "gt-cp-constexpr.h"
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 0f7e08f..ecf2a5d 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6884,6 +6884,8 @@  extern tree register_constexpr_fundef           (tree, tree);
 extern bool check_constexpr_ctor_body           (tree, tree, bool);
 extern tree ensure_literal_type_for_constexpr_object (tree);
 extern bool potential_constant_expression       (tree);
+extern bool potential_nondependent_constant_expression (tree);
+extern bool potential_nondependent_static_init_expression (tree);
 extern bool potential_static_init_expression    (tree);
 extern bool potential_rvalue_constant_expression (tree);
 extern bool require_potential_constant_expression (tree);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 2d93a5c..2871f33 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -5655,8 +5655,7 @@  instantiate_non_dependent_expr_sfinae (tree expr, tsubst_flags_t complain)
 
      as two declarations of the same function, for example.  */
   if (processing_template_decl
-      && !instantiation_dependent_expression_p (expr)
-      && potential_constant_expression (expr))
+      && potential_nondependent_constant_expression (expr))
     {
       processing_template_decl_sentinel s;
       expr = instantiate_non_dependent_expr_internal (expr, complain);
@@ -5680,8 +5679,7 @@  instantiate_non_dependent_or_null (tree expr)
     return NULL_TREE;
   if (processing_template_decl)
     {
-      if (instantiation_dependent_expression_p (expr)
-	  || !potential_constant_expression (expr))
+      if (!potential_nondependent_constant_expression (expr))
 	expr = NULL_TREE;
       else
 	{
@@ -6240,10 +6238,8 @@  convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
   if (TYPE_REF_OBJ_P (type)
       && has_value_dependent_address (expr))
     /* If we want the address and it's value-dependent, don't fold.  */;
-  else if (!type_unknown_p (expr)
-	   && processing_template_decl
-	   && !instantiation_dependent_expression_p (expr)
-	   && potential_constant_expression (expr))
+  else if (processing_template_decl
+	   && potential_nondependent_constant_expression (expr))
     non_dep = true;
   if (error_operand_p (expr))
     return error_mark_node;