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.
commit 0897b3e9b5be7fc3adbe96d871876fdb8452d2a9
Author: Jason Merrill <ja...@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 <ja...@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;