Patchwork C++ PATCH for c++/53202 (copy constructor not run in C++11)

login
register
mail settings
Submitter Jason Merrill
Date June 25, 2012, 3:44 p.m.
Message ID <4FE8876B.6010007@redhat.com>
Download mbox | patch
Permalink /patch/167142/
State New
Headers show

Comments

Jason Merrill - June 25, 2012, 3:44 p.m.
The code that collects base initializers in a constructor declared 
constexpr was checking potential_constant_expression and then discarding 
an initializer for an empty base if true.  But 
potential_constant_expression only looks at whether a function is 
declared constexpr, not whether the call actually turns out to be 
constant; to determine that we need to keep the call around until we 
actually try to expand it.

Tested x86_64-pc-linux-gnu, applied to 4.7 and trunk.

Patch

commit 2e6c5d723ff7407704f2cbd343383991b498fb5b
Author: jason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Date:   Mon Jun 25 15:17:59 2012 +0000

    	PR c++/53202
    	* semantics.c (build_data_member_initialization): Always keep
    	initializer for empty base.
    	(cxx_eval_bare_aggregate): Discard it here.
    
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index ee41861..2d64a66 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -5838,12 +5838,9 @@  build_data_member_initialization (tree t, VEC(constructor_elt,gc) **vec)
 	member = op;
       else
 	{
-	  /* We don't put out anything for an empty base.  */
+	  /* This is an initializer for an empty base; keep it for now so
+	     we can check it in cxx_eval_bare_aggregate.  */
 	  gcc_assert (is_empty_class (TREE_TYPE (TREE_TYPE (member))));
-	  /* But if the initializer isn't constexpr, leave it in so we
-	     complain later.  */
-	  if (potential_constant_expression (init))
-	    return true;
 	}
     }
   if (TREE_CODE (member) == ADDR_EXPR)
@@ -7064,6 +7061,12 @@  cxx_eval_bare_aggregate (const constexpr_call *call, tree t,
 	  constructor_elt *inner = base_field_constructor_elt (n, ce->index);
 	  inner->value = elt;
 	}
+      else if (TREE_CODE (ce->index) == NOP_EXPR)
+	{
+	  /* This is an initializer for an empty base; now that we've
+	     checked that it's constant, we can ignore it.  */
+	  gcc_assert (is_empty_class (TREE_TYPE (TREE_TYPE (ce->index))));
+	}
       else
 	CONSTRUCTOR_APPEND_ELT (n, ce->index, elt);
     }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-tuple.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-tuple.C
new file mode 100644
index 0000000..f59cd84
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-tuple.C
@@ -0,0 +1,106 @@ 
+// PR c++/53202
+// { dg-do run { target c++11 } }
+
+#include <tuple>
+
+template<typename Callable>
+  struct Bind_simple
+  {
+    explicit
+    Bind_simple(const Callable& callable)
+    : _M_bound(callable)
+    { }
+
+    Bind_simple(const Bind_simple&) = default;
+    Bind_simple(Bind_simple&&) = default;
+
+    auto operator()() -> decltype((*(Callable*)0)())
+    {
+      return std::get<0>(_M_bound)();
+    }
+
+  private:
+
+    std::tuple<Callable> _M_bound;
+  };
+
+template<typename Callable>
+  Bind_simple<Callable>
+  bind_simple(Callable& callable)
+  {
+    return Bind_simple<Callable>(callable);
+  }
+
+struct thread
+{
+  struct ImplBase { };
+
+  template<typename T>
+    struct Impl : ImplBase {
+      T t;
+      Impl(T&& t) : t(std::move(t)) { }
+    };
+
+  template<typename T>
+    thread(T& t)
+    {
+      auto p = make_routine(bind_simple(t));
+
+      p->t();
+
+      delete p;
+    }
+
+  template<typename Callable>
+    Impl<Callable>*
+    make_routine(Callable&& f)
+    {
+      return new Impl<Callable>(std::forward<Callable>(f));
+    }
+};
+
+
+int c;
+class background_hello
+{
+public:
+    background_hello()
+    {
+      __builtin_printf("default ctor called, this=%p\n", this);
+      ++c;
+    }
+
+    background_hello(const background_hello &)
+    {
+      __builtin_printf("copy ctor called\n");
+      ++c;
+    }
+
+    background_hello(background_hello &&)
+    {
+      __builtin_printf("move ctor called\n");
+      ++c;
+    }
+
+    void operator ()() const
+    {
+      __builtin_printf("void background_hello::operator()() called, this=%p\n", this);
+    }
+
+    ~background_hello()
+    {
+      __builtin_printf("destructor called, this=%p\n", this);
+      --c;
+    }
+
+};
+
+int main()
+{
+  {
+    background_hello bh;
+    thread t(bh);
+  }
+  if (c != 0)
+    __builtin_abort ();
+}