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

Reply via email to