In this testcase, we consider the initializer of b to decide if it's value-dependent, but the initializer mentions b, so we were recursing infinitely. But if we're interested in the address, we don't care about the value; we already handle that appropriately in the constexpr code, this patch updates value_dependent_expression_p accordingly.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit c7321d4e2c36f6e336cfa1eb27c4f5434e9dd349 Author: Jason Merrill <ja...@redhat.com> Date: Wed Dec 6 15:27:33 2017 -0500 PR c++/82115 - ICE with variable initialized with its own address. * pt.c (value_dependent_expression_p): Add lval parameter. Don't consider DECL_INITIAL if it's true. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index e77241f3d97..575255d64e7 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6542,7 +6542,7 @@ extern bool type_dependent_object_expression_p (tree); extern bool any_type_dependent_arguments_p (const vec<tree, va_gc> *); 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 value_dependent_expression_p (tree, bool = false); extern bool instantiation_dependent_expression_p (tree); extern bool instantiation_dependent_uneval_expression_p (tree); extern bool any_value_dependent_elements_p (const_tree); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 685f34a735d..252712e80f2 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -23916,7 +23916,7 @@ instantiation_dependent_scope_ref_p (tree t) can be tested for value dependence. */ bool -value_dependent_expression_p (tree expression) +value_dependent_expression_p (tree expression, bool lval /* = false */) { if (!processing_template_decl || expression == NULL_TREE) return false; @@ -23950,6 +23950,7 @@ value_dependent_expression_p (tree expression) /* A non-type template parm. */ if (DECL_TEMPLATE_PARM_P (expression)) return true; + gcc_checking_assert (!lval); return value_dependent_expression_p (DECL_INITIAL (expression)); case VAR_DECL: @@ -23959,7 +23960,8 @@ value_dependent_expression_p (tree expression) Note that a non-dependent parenthesized initializer will have already been replaced with its constant value, so if we see a TREE_LIST it must be dependent. */ - if (DECL_INITIAL (expression) + if (!lval + && DECL_INITIAL (expression) && decl_constant_var_p (expression) && (TREE_CODE (DECL_INITIAL (expression)) == TREE_LIST /* cp_finish_decl doesn't fold reference initializers. */ @@ -23969,7 +23971,7 @@ value_dependent_expression_p (tree expression) if (DECL_HAS_VALUE_EXPR_P (expression)) { tree value_expr = DECL_VALUE_EXPR (expression); - if (value_dependent_expression_p (value_expr)) + if (value_dependent_expression_p (value_expr, lval)) return true; } return false; @@ -24005,7 +24007,7 @@ value_dependent_expression_p (tree expression) if (TREE_CODE (expression) == TREE_LIST) return any_value_dependent_elements_p (expression); - return value_dependent_expression_p (expression); + return value_dependent_expression_p (expression, lval); } case SIZEOF_EXPR: @@ -24039,7 +24041,7 @@ value_dependent_expression_p (tree expression) return instantiation_dependent_scope_ref_p (expression); case COMPONENT_REF: - return (value_dependent_expression_p (TREE_OPERAND (expression, 0)) + return (value_dependent_expression_p (TREE_OPERAND (expression, 0), lval) || value_dependent_expression_p (TREE_OPERAND (expression, 1))); case NONTYPE_ARGUMENT_PACK: @@ -24087,7 +24089,7 @@ value_dependent_expression_p (tree expression) case ADDR_EXPR: { tree op = TREE_OPERAND (expression, 0); - return (value_dependent_expression_p (op) + return (value_dependent_expression_p (op, true) || has_value_dependent_address (op)); } diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-self1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-self1.C new file mode 100644 index 00000000000..96f1d18146a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-self1.C @@ -0,0 +1,14 @@ +// PR c++/82115 +// { dg-do compile { target c++11 } } + +struct A { int const u = 0; }; + +struct B : A +{ + constexpr B (int const *p) : v (p) {} + int const *v; +}; + +constexpr B b (&b.u); + +template < typename > void foo () { b; }