re PR c++/54532 ([C++0x][constexpr] internal error when initializing static constexpr...
authorJason Merrill <jason@redhat.com>
Thu, 21 Mar 2013 03:25:35 +0000 (23:25 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Thu, 21 Mar 2013 03:25:35 +0000 (23:25 -0400)
PR c++/54532
* expr.c (cplus_expand_constant): Do nothing if the class is
incomplete.
* semantics.c (reduced_constant_expression_p): Allow PTRMEM_CST.
* typeck2.c (store_init_value): Use reduced_constant_expression_p.
* decl.c (maybe_register_incomplete_var): Handle PTRMEM_CST.
(complete_vars): Likewise.

From-SVN: r196852

gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/cp/expr.c
gcc/cp/semantics.c
gcc/cp/typeck2.c
gcc/testsuite/g++.dg/cpp0x/constexpr-static11.C [new file with mode: 0644]

index 719f70c693ac7be42befa723068518b9f8ae9b7e..64a085c7fb5ea5b7cf577603cbb3abd5f34f5d87 100644 (file)
@@ -1,5 +1,13 @@
 2013-03-20  Jason Merrill  <jason@redhat.com>
 
+       PR c++/54532
+       * expr.c (cplus_expand_constant): Do nothing if the class is
+       incomplete.
+       * semantics.c (reduced_constant_expression_p): Allow PTRMEM_CST.
+       * typeck2.c (store_init_value): Use reduced_constant_expression_p.
+       * decl.c (maybe_register_incomplete_var): Handle PTRMEM_CST.
+       (complete_vars): Likewise.
+
        * name-lookup.c (get_anonymous_namespace_name): Never use
        get_file_function_name.
 
index facaae7ff19c3e76709cf7deb067a62dbb7ba171..4ccb5414cc6a810149f78fe6a6249c8aa4567bad 100644 (file)
@@ -14018,7 +14018,10 @@ grokmethod (cp_decl_specifier_seq *declspecs,
 \f
 
 /* VAR is a VAR_DECL.  If its type is incomplete, remember VAR so that
-   we can lay it out later, when and if its type becomes complete.  */
+   we can lay it out later, when and if its type becomes complete.
+
+   Also handle constexpr pointer to member variables where the initializer
+   is an unlowered PTRMEM_CST because the class isn't complete yet.  */
 
 void
 maybe_register_incomplete_var (tree var)
@@ -14043,6 +14046,15 @@ maybe_register_incomplete_var (tree var)
          incomplete_var iv = {var, inner_type};
          vec_safe_push (incomplete_vars, iv);
        }
+      else if (TYPE_PTRMEM_P (inner_type)
+              && DECL_INITIAL (var)
+              && TREE_CODE (DECL_INITIAL (var)) == PTRMEM_CST)
+       {
+         tree context = TYPE_PTRMEM_CLASS_TYPE (inner_type);
+         gcc_assert (TYPE_BEING_DEFINED (context));
+         incomplete_var iv = {var, context};
+         vec_safe_push (incomplete_vars, iv);
+       }
     }
 }
 
@@ -14062,10 +14074,17 @@ complete_vars (tree type)
        {
          tree var = iv->decl;
          tree type = TREE_TYPE (var);
-         /* Complete the type of the variable.  The VAR_DECL itself
-            will be laid out in expand_expr.  */
-         complete_type (type);
-         cp_apply_type_quals_to_decl (cp_type_quals (type), var);
+
+         if (TYPE_PTRMEM_P (type))
+           DECL_INITIAL (var) = cplus_expand_constant (DECL_INITIAL (var));
+         else
+           {
+             /* Complete the type of the variable.  The VAR_DECL itself
+                will be laid out in expand_expr.  */
+             complete_type (type);
+             cp_apply_type_quals_to_decl (cp_type_quals (type), var);
+           }
+
          /* Remove this entry from the list.  */
          incomplete_vars->unordered_remove (ix);
        }
index ffd18ca67850b48fa82fa4d6fb99729e94f59bf3..f15b049baf8aae8c39e26dba084062d9d1b7d959 100644 (file)
@@ -43,6 +43,10 @@ cplus_expand_constant (tree cst)
        /* Find the member.  */
        member = PTRMEM_CST_MEMBER (cst);
 
+       /* We can't lower this until the class is complete.  */
+       if (!COMPLETE_TYPE_P (DECL_CONTEXT (member)))
+         return cst;
+
        if (TREE_CODE (member) == FIELD_DECL)
          {
            /* Find the offset for the field.  */
index 5143e4bd5822b0985e1fac3087a32985f2cc8c29..3691d8620492d3f5b2548ef166740f93c9028276 100644 (file)
@@ -6838,6 +6838,9 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t,
 bool
 reduced_constant_expression_p (tree t)
 {
+  if (TREE_CODE (t) == PTRMEM_CST)
+    /* Even if we can't lower this yet, it's constant.  */
+    return true;
   /* FIXME are we calling this too much?  */
   return initializer_constant_valid_p (t, TREE_TYPE (t)) != NULL_TREE;
 }
index 3bac67cf1192f567fb1b3988b9984973553c7e29..6ef46a1b00ffa3dcaaabbef17b08ab675426a137 100644 (file)
@@ -792,7 +792,7 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
      will perform the dynamic initialization.  */
   if (value != error_mark_node
       && (TREE_SIDE_EFFECTS (value)
-          || ! initializer_constant_valid_p (value, TREE_TYPE (value))))
+         || ! reduced_constant_expression_p (value)))
     {
       if (TREE_CODE (type) == ARRAY_TYPE
          && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (type)))
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-static11.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-static11.C
new file mode 100644 (file)
index 0000000..91cc25a
--- /dev/null
@@ -0,0 +1,14 @@
+// PR c++/54532
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert(X,#X)
+
+struct A {
+  int i;
+  constexpr static int A::*p = &A::i;
+};
+
+constexpr A a = { 42 };
+SA(a.*A::p == 42);
+
+constexpr int A::* A::p;