We changed months back to use the pre-generic form for constexpr evaluation,
but explain_invalid_constexpr_fn was still using DECL_SAVED_TREE.  This
mostly works, but misses some issues due to folding.  So with this patch we
save the pre-generic form of constexpr functions even when we know they
can't produce a constant result.

Tested x86_64-pc-linux-gnu, applying to trunk.

        * constexpr.c (register_constexpr_fundef): Do store the body of a
        template instantiation that is not potentially constant.
        (explain_invalid_constexpr_fn): Look it up.
        (cxx_eval_call_expression): Check fundef->result.
---
 gcc/cp/constexpr.c                            | 27 +++++++++++++------
 gcc/testsuite/g++.dg/cpp0x/constexpr-nsdmi1.C | 12 +++++++++
 2 files changed, 31 insertions(+), 8 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-nsdmi1.C

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index f3f03e7d621..87d78d26728 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -885,16 +885,16 @@ register_constexpr_fundef (tree fun, tree body)
       return NULL;
     }
 
-  if (!potential_rvalue_constant_expression (massaged))
-    {
-      if (!DECL_GENERATED_P (fun))
-       require_potential_rvalue_constant_expression (massaged);
-      return NULL;
-    }
+  bool potential = potential_rvalue_constant_expression (massaged);
+  if (!potential && !DECL_GENERATED_P (fun))
+    require_potential_rvalue_constant_expression (massaged);
 
   if (DECL_CONSTRUCTOR_P (fun)
       && cx_check_missing_mem_inits (DECL_CONTEXT (fun),
                                     massaged, !DECL_GENERATED_P (fun)))
+    potential = false;
+
+  if (!potential && !DECL_GENERATED_P (fun))
     return NULL;
 
   /* Create the constexpr function table if necessary.  */
@@ -917,6 +917,12 @@ register_constexpr_fundef (tree fun, tree body)
   if (clear_ctx)
     DECL_CONTEXT (DECL_RESULT (fun)) = NULL_TREE;
 
+  if (!potential)
+    /* For a template instantiation, we want to remember the pre-generic body
+       for explain_invalid_constexpr_fn, but do tell cxx_eval_call_expression
+       that it doesn't need to bother trying to expand the function.  */
+    entry.result = error_mark_node;
+
   gcc_assert (*slot == NULL);
   *slot = ggc_alloc<constexpr_fundef> ();
   **slot = entry;
@@ -962,11 +968,15 @@ explain_invalid_constexpr_fn (tree fun)
     {
       /* Then if it's OK, the body.  */
       if (!DECL_DECLARED_CONSTEXPR_P (fun)
-         && !LAMBDA_TYPE_P (CP_DECL_CONTEXT (fun)))
+         && DECL_DEFAULTED_FN (fun))
        explain_implicit_non_constexpr (fun);
       else
        {
-         body = massage_constexpr_body (fun, DECL_SAVED_TREE (fun));
+         if (constexpr_fundef *fd = retrieve_constexpr_fundef (fun))
+           body = fd->body;
+         else
+           body = DECL_SAVED_TREE (fun);
+         body = massage_constexpr_body (fun, body);
          require_potential_rvalue_constant_expression (body);
          if (DECL_CONSTRUCTOR_P (fun))
            cx_check_missing_mem_inits (DECL_CONTEXT (fun), body, true);
@@ -1919,6 +1929,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree 
t,
     {
       new_call.fundef = retrieve_constexpr_fundef (fun);
       if (new_call.fundef == NULL || new_call.fundef->body == NULL
+         || new_call.fundef->result == error_mark_node
          || fun == current_function_decl)
         {
          if (!ctx->quiet)
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-nsdmi1.C 
b/gcc/testsuite/g++.dg/cpp0x/constexpr-nsdmi1.C
new file mode 100644
index 00000000000..b94cf3099f4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-nsdmi1.C
@@ -0,0 +1,12 @@
+// PR c++/79592
+// { dg-do compile { target c++11 } }
+
+struct pthread_mutex {
+  void *m_ptr;
+};
+
+struct M {
+  pthread_mutex m = { ((void *) 1LL) }; // { dg-error "reinterpret_cast" }
+};
+
+constexpr M m;                 // { dg-error "M::M" }

base-commit: 7484780e06a758b7a02f270ae8af30fd2c11fdef
-- 
2.18.1

Reply via email to