On Wed, Dec 6, 2017 at 4:40 PM, Jason Merrill <ja...@redhat.com> wrote: > 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.
I've been uneasy about this approach, since it isn't necessarily true that we don't care about the value; we might indirect later to get back to the value. So instead, this patch sets a flag to indicate a constant variable with a dependent initializer. The first patch is after reverting the other patch; the second is the combination. I also noticed that type_dependent_init_p is unnecessary since type-dependence implies value-dependence. Tested x86_64-pc-linux-gnu, applying to trunk.
commit 18e711b75363ec2f304ee8fc162efea968f8f8af Author: Jason Merrill <ja...@redhat.com> Date: Fri Dec 8 07:45:02 2017 -0500 PR c++/82115 - ICE with variable initialized with its own address. * cp-tree.h (struct lang_decl_base): Add dependent_init_p. (DECL_DEPENDENT_INIT_P, SET_DECL_DEPENDENT_INIT_P): New. * decl.c (cp_finish_decl): Set it. (duplicate_decls): Copy it. * pt.c (tsubst_decl): Clear it. (value_dependent_expression_p): Check it. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 736c4844bcf..a7acf49986f 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -2449,7 +2449,8 @@ struct GTY(()) lang_decl_base { unsigned u2sel : 1; unsigned concept_p : 1; /* applies to vars and functions */ unsigned var_declared_inline_p : 1; /* var */ - /* 2 spare bits */ + unsigned dependent_init_p : 1; /* var */ + /* 1 spare bit */ }; /* True for DECL codes which have template info and access. */ @@ -3879,6 +3880,13 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE))->u.base.var_declared_inline_p \ = true) +/* True if NODE is a variable with a value-dependent initializer. */ +#define DECL_DEPENDENT_INIT_P(NODE) \ + (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE)) \ + && DECL_LANG_SPECIFIC (NODE)->u.base.dependent_init_p) +#define SET_DECL_DEPENDENT_INIT_P(NODE, X) \ + (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE))->u.base.dependent_init_p = (X)) + /* Nonzero if NODE is an artificial VAR_DECL for a C++17 structured binding declaration or one of VAR_DECLs for the user identifiers in it. */ #define DECL_DECOMPOSITION_P(NODE) \ diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 99b22dc878c..3601fa117c7 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -2120,6 +2120,8 @@ next_arg:; DECL_INITIALIZED_P (newdecl) |= DECL_INITIALIZED_P (olddecl); DECL_NONTRIVIALLY_INITIALIZED_P (newdecl) |= DECL_NONTRIVIALLY_INITIALIZED_P (olddecl); + if (DECL_DEPENDENT_INIT_P (olddecl)) + SET_DECL_DEPENDENT_INIT_P (newdecl, true); DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (newdecl) |= DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (olddecl); if (DECL_CLASS_SCOPE_P (olddecl)) @@ -6910,14 +6912,18 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, then it can be used in future constant expressions, so its value must be available. */ + bool dep_init = false; + if (!VAR_P (decl) || type_dependent_p) /* We can't do anything if the decl has dependent type. */; + else if (!init && is_concept_var (decl)) + error ("variable concept has no initializer"); else if (init && init_const_expr_p && TREE_CODE (type) != REFERENCE_TYPE && decl_maybe_constant_var_p (decl) - && !type_dependent_init_p (init) - && !value_dependent_init_p (init)) + && !(dep_init = (type_dependent_init_p (init) + || value_dependent_init_p (init)))) { /* This variable seems to be a non-dependent constant, so process its initializer. If check_initializer returns non-null the @@ -6929,8 +6935,6 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, init = NULL_TREE; release_tree_vector (cleanups); } - else if (!init && is_concept_var (decl)) - error ("variable concept has no initializer"); else if (!DECL_PRETTY_FUNCTION_P (decl)) { /* Deduce array size even if the initializer is dependent. */ @@ -6944,6 +6948,11 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, if (init) DECL_INITIAL (decl) = init; + if (dep_init) + { + retrofit_lang_decl (decl); + SET_DECL_DEPENDENT_INIT_P (decl, true); + } return; } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 8cb90dca761..b5be9807ea9 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -13135,6 +13135,9 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) DECL_SIZE (r) = DECL_SIZE_UNIT (r) = 0; if (VAR_P (r)) { + if (DECL_LANG_SPECIFIC (r)) + SET_DECL_DEPENDENT_INIT_P (r, false); + SET_DECL_MODE (r, VOIDmode); /* Possibly limit visibility based on template args. */ @@ -23960,17 +23963,10 @@ value_dependent_expression_p (tree expression) case VAR_DECL: /* A constant with literal type and is initialized - with an expression that is value-dependent. - - 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) - && decl_constant_var_p (expression) - && (TREE_CODE (DECL_INITIAL (expression)) == TREE_LIST - /* cp_finish_decl doesn't fold reference initializers. */ - || TREE_CODE (TREE_TYPE (expression)) == REFERENCE_TYPE - || value_dependent_expression_p (DECL_INITIAL (expression)))) + with an expression that is value-dependent. */ + if (DECL_DEPENDENT_INIT_P (expression) + /* FIXME cp_finish_decl doesn't fold reference initializers. */ + || TREE_CODE (TREE_TYPE (expression)) == REFERENCE_TYPE) return true; if (DECL_HAS_VALUE_EXPR_P (expression)) { diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-self1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-self1.C index 96f1d18146a..32a10af49a6 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-self1.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-self1.C @@ -12,3 +12,8 @@ struct B : A constexpr B b (&b.u); template < typename > void foo () { b; } + +template < typename T> void foo2 () { + constexpr B b2 = &b2.u; + b2; +}
commit d3b6bd81a9f879d5aae72ce74fce6ffddd28a31f Author: Jason Merrill <ja...@redhat.com> Date: Fri Dec 8 07:45:02 2017 -0500 PR c++/82115 - ICE with variable initialized with its own address. * cp-tree.h (struct lang_decl_base): Add dependent_init_p. (DECL_DEPENDENT_INIT_P, SET_DECL_DEPENDENT_INIT_P): New. * decl.c (cp_finish_decl): Set it. (duplicate_decls): Copy it. * pt.c (tsubst_decl): Clear it. (value_dependent_expression_p): Check it. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 708d172bf61..a7acf49986f 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -2449,7 +2449,8 @@ struct GTY(()) lang_decl_base { unsigned u2sel : 1; unsigned concept_p : 1; /* applies to vars and functions */ unsigned var_declared_inline_p : 1; /* var */ - /* 2 spare bits */ + unsigned dependent_init_p : 1; /* var */ + /* 1 spare bit */ }; /* True for DECL codes which have template info and access. */ @@ -3879,6 +3880,13 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE))->u.base.var_declared_inline_p \ = true) +/* True if NODE is a variable with a value-dependent initializer. */ +#define DECL_DEPENDENT_INIT_P(NODE) \ + (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE)) \ + && DECL_LANG_SPECIFIC (NODE)->u.base.dependent_init_p) +#define SET_DECL_DEPENDENT_INIT_P(NODE, X) \ + (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE))->u.base.dependent_init_p = (X)) + /* Nonzero if NODE is an artificial VAR_DECL for a C++17 structured binding declaration or one of VAR_DECLs for the user identifiers in it. */ #define DECL_DECOMPOSITION_P(NODE) \ @@ -6542,7 +6550,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, bool = false); +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); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 99b22dc878c..3601fa117c7 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -2120,6 +2120,8 @@ next_arg:; DECL_INITIALIZED_P (newdecl) |= DECL_INITIALIZED_P (olddecl); DECL_NONTRIVIALLY_INITIALIZED_P (newdecl) |= DECL_NONTRIVIALLY_INITIALIZED_P (olddecl); + if (DECL_DEPENDENT_INIT_P (olddecl)) + SET_DECL_DEPENDENT_INIT_P (newdecl, true); DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (newdecl) |= DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (olddecl); if (DECL_CLASS_SCOPE_P (olddecl)) @@ -6910,14 +6912,18 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, then it can be used in future constant expressions, so its value must be available. */ + bool dep_init = false; + if (!VAR_P (decl) || type_dependent_p) /* We can't do anything if the decl has dependent type. */; + else if (!init && is_concept_var (decl)) + error ("variable concept has no initializer"); else if (init && init_const_expr_p && TREE_CODE (type) != REFERENCE_TYPE && decl_maybe_constant_var_p (decl) - && !type_dependent_init_p (init) - && !value_dependent_init_p (init)) + && !(dep_init = (type_dependent_init_p (init) + || value_dependent_init_p (init)))) { /* This variable seems to be a non-dependent constant, so process its initializer. If check_initializer returns non-null the @@ -6929,8 +6935,6 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, init = NULL_TREE; release_tree_vector (cleanups); } - else if (!init && is_concept_var (decl)) - error ("variable concept has no initializer"); else if (!DECL_PRETTY_FUNCTION_P (decl)) { /* Deduce array size even if the initializer is dependent. */ @@ -6944,6 +6948,11 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, if (init) DECL_INITIAL (decl) = init; + if (dep_init) + { + retrofit_lang_decl (decl); + SET_DECL_DEPENDENT_INIT_P (decl, true); + } return; } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 0cf6509c247..b5be9807ea9 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -13135,6 +13135,9 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) DECL_SIZE (r) = DECL_SIZE_UNIT (r) = 0; if (VAR_P (r)) { + if (DECL_LANG_SPECIFIC (r)) + SET_DECL_DEPENDENT_INIT_P (r, false); + SET_DECL_MODE (r, VOIDmode); /* Possibly limit visibility based on template args. */ @@ -23922,7 +23925,7 @@ instantiation_dependent_scope_ref_p (tree t) can be tested for value dependence. */ bool -value_dependent_expression_p (tree expression, bool lval /* = false */) +value_dependent_expression_p (tree expression) { if (!processing_template_decl || expression == NULL_TREE) return false; @@ -23956,28 +23959,19 @@ value_dependent_expression_p (tree expression, bool lval /* = false */) /* 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: /* A constant with literal type and is initialized - with an expression that is value-dependent. - - 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 (!lval - && DECL_INITIAL (expression) - && decl_constant_var_p (expression) - && (TREE_CODE (DECL_INITIAL (expression)) == TREE_LIST - /* cp_finish_decl doesn't fold reference initializers. */ - || TREE_CODE (TREE_TYPE (expression)) == REFERENCE_TYPE - || value_dependent_expression_p (DECL_INITIAL (expression)))) + with an expression that is value-dependent. */ + if (DECL_DEPENDENT_INIT_P (expression) + /* FIXME cp_finish_decl doesn't fold reference initializers. */ + || TREE_CODE (TREE_TYPE (expression)) == REFERENCE_TYPE) return true; if (DECL_HAS_VALUE_EXPR_P (expression)) { tree value_expr = DECL_VALUE_EXPR (expression); - if (value_dependent_expression_p (value_expr, lval)) + if (value_dependent_expression_p (value_expr)) return true; } return false; @@ -24013,7 +24007,7 @@ value_dependent_expression_p (tree expression, bool lval /* = false */) if (TREE_CODE (expression) == TREE_LIST) return any_value_dependent_elements_p (expression); - return value_dependent_expression_p (expression, lval); + return value_dependent_expression_p (expression); } case SIZEOF_EXPR: @@ -24047,7 +24041,7 @@ value_dependent_expression_p (tree expression, bool lval /* = false */) return instantiation_dependent_scope_ref_p (expression); case COMPONENT_REF: - return (value_dependent_expression_p (TREE_OPERAND (expression, 0), lval) + return (value_dependent_expression_p (TREE_OPERAND (expression, 0)) || value_dependent_expression_p (TREE_OPERAND (expression, 1))); case NONTYPE_ARGUMENT_PACK: @@ -24095,7 +24089,7 @@ value_dependent_expression_p (tree expression, bool lval /* = false */) case ADDR_EXPR: { tree op = TREE_OPERAND (expression, 0); - return (value_dependent_expression_p (op, true) + return (value_dependent_expression_p (op) || 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 index 96f1d18146a..32a10af49a6 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-self1.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-self1.C @@ -12,3 +12,8 @@ struct B : A constexpr B b (&b.u); template < typename > void foo () { b; } + +template < typename T> void foo2 () { + constexpr B b2 = &b2.u; + b2; +}
commit eaf85e22f4f3e7b78e68e2cfac5c49eb650e06dd Author: Jason Merrill <ja...@redhat.com> Date: Fri Dec 8 16:05:32 2017 -0500 Remove type_dependent_init_p. * decl.c (value_dependent_init_p): Check the type of a CONSTRUCTOR. (type_dependent_init_p): Remove. diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 3601fa117c7..445c23c5dac 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -6644,38 +6644,6 @@ initialize_artificial_var (tree decl, vec<constructor_elt, va_gc> *v) } /* INIT is the initializer for a variable, as represented by the - parser. Returns true iff INIT is type-dependent. */ - -static bool -type_dependent_init_p (tree init) -{ - if (TREE_CODE (init) == TREE_LIST) - /* A parenthesized initializer, e.g.: int i (3, 2); ? */ - return any_type_dependent_elements_p (init); - else if (TREE_CODE (init) == CONSTRUCTOR) - /* A brace-enclosed initializer, e.g.: int i = { 3 }; ? */ - { - if (dependent_type_p (TREE_TYPE (init))) - return true; - - vec<constructor_elt, va_gc> *elts; - size_t nelts; - size_t i; - - elts = CONSTRUCTOR_ELTS (init); - nelts = vec_safe_length (elts); - for (i = 0; i < nelts; ++i) - if (type_dependent_init_p ((*elts)[i].value)) - return true; - } - else - /* It must be a simple expression, e.g., int i = 3; */ - return type_dependent_expression_p (init); - - return false; -} - -/* INIT is the initializer for a variable, as represented by the parser. Returns true iff INIT is value-dependent. */ static bool @@ -6687,6 +6655,9 @@ value_dependent_init_p (tree init) else if (TREE_CODE (init) == CONSTRUCTOR) /* A brace-enclosed initializer, e.g.: int i = { 3 }; ? */ { + if (dependent_type_p (TREE_TYPE (init))) + return true; + vec<constructor_elt, va_gc> *elts; size_t nelts; size_t i; @@ -6922,8 +6893,7 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, && init_const_expr_p && TREE_CODE (type) != REFERENCE_TYPE && decl_maybe_constant_var_p (decl) - && !(dep_init = (type_dependent_init_p (init) - || value_dependent_init_p (init)))) + && !(dep_init = value_dependent_init_p (init))) { /* This variable seems to be a non-dependent constant, so process its initializer. If check_initializer returns non-null the