Add redirect_error.
diff --git a/asio/include/asio.hpp b/asio/include/asio.hpp
index ae15132..cb46bde 100644
--- a/asio/include/asio.hpp
+++ b/asio/include/asio.hpp
@@ -108,6 +108,7 @@
 #include "asio/read.hpp"
 #include "asio/read_at.hpp"
 #include "asio/read_until.hpp"
+#include "asio/redirect_error.hpp"
 #include "asio/seq_packet_socket_service.hpp"
 #include "asio/serial_port.hpp"
 #include "asio/serial_port_base.hpp"
diff --git a/asio/include/asio/impl/await.hpp b/asio/include/asio/impl/await.hpp
index 3630875..a253a1e 100644
--- a/asio/include/asio/impl/await.hpp
+++ b/asio/include/asio/impl/await.hpp
@@ -396,7 +396,7 @@
   void operator()(std::exception_ptr ex)
   {
     awaiter_ptr ptr(std::move(awaiter_));
-    if (ec)
+    if (ex)
       awaitee_->set_exception(ex);
     else
       awaitee_->return_void();
@@ -415,10 +415,7 @@
   void operator()(T t)
   {
     awaiter_ptr ptr(std::move(awaiter_));
-    if (ec)
-      awaitee_->set_exception(ex);
-    else
-      awaitee_->return_value(std::forward<T>(t));
+    awaitee_->return_value(std::forward<T>(t));
     awaitee_->wake_caller();
     ptr->rethrow_exception();
   }
@@ -453,7 +450,7 @@
   void operator()(std::exception_ptr ex, T t)
   {
     awaiter_ptr ptr(std::move(awaiter_));
-    if (ec)
+    if (ex)
       awaitee_->set_exception(ex);
     else
       awaitee_->return_value(std::forward<T>(t));
diff --git a/asio/include/asio/impl/redirect_error.hpp b/asio/include/asio/impl/redirect_error.hpp
new file mode 100644
index 0000000..45a3c4f
--- /dev/null
+++ b/asio/include/asio/impl/redirect_error.hpp
@@ -0,0 +1,256 @@
+//
+// impl/redirect_error.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IMPL_REDIRECT_ERROR_HPP
+#define ASIO_IMPL_REDIRECT_ERROR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/associated_executor.hpp"
+#include "asio/associated_allocator.hpp"
+#include "asio/async_result.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/variadic_templates.hpp"
+#include "asio/handler_type.hpp"
+#include "asio/system_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+  // Class to adapt a redirect_error_t as a completion handler.
+  template <typename Handler>
+  class redirect_error_handler
+  {
+  public:
+    template <typename CompletionToken>
+    redirect_error_handler(redirect_error_t<CompletionToken> e)
+      : ec_(e.ec_),
+        handler_(ASIO_MOVE_CAST(CompletionToken)(e.token_))
+    {
+    }
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+    template <typename... Args>
+    void operator()(ASIO_MOVE_ARG(Args)... args)
+    {
+      handler_(ASIO_MOVE_CAST(Args)(args)...);
+    }
+
+    template <typename... Args>
+    void operator()(const asio::error_code& ec,
+        ASIO_MOVE_ARG(Args)... args)
+    {
+      ec_ = ec;
+      handler_(ASIO_MOVE_CAST(Args)(args)...);
+    }
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+    void operator()()
+    {
+      handler_();
+    }
+
+    void operator()(const asio::error_code& ec)
+    {
+      ec_ = ec;
+      handler_();
+    }
+
+#define ASIO_PRIVATE_REDIRECT_ERROR_DEF(n) \
+    template <ASIO_VARIADIC_TPARAMS(n)> \
+    void operator()(ASIO_VARIADIC_MOVE_PARAMS(n)) \
+    { \
+      handler_(ASIO_VARIADIC_MOVE_ARGS(n)); \
+    } \
+    \
+    template <ASIO_VARIADIC_TPARAMS(n)> \
+    void operator()(const asio::error_code& ec, \
+        ASIO_VARIADIC_MOVE_PARAMS(n)) \
+    { \
+      ec_ = ec; \
+      handler_(ASIO_VARIADIC_MOVE_ARGS(n)); \
+    } \
+    /**/
+    ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_REDIRECT_ERROR_DEF)
+#undef ASIO_PRIVATE_REDIRECT_ERROR_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+  //private:
+    asio::error_code& ec_;
+    Handler handler_;
+  };
+
+  template <typename Handler>
+  inline void* asio_handler_allocate(std::size_t size,
+      redirect_error_handler<Handler>* this_handler)
+  {
+    return asio_handler_alloc_helpers::allocate(
+        size, this_handler->handler_);
+  }
+
+  template <typename Handler>
+  inline void* asio_handler_deallocate(std::size_t size,
+      redirect_error_handler<Handler>* this_handler)
+  {
+    asio_handler_alloc_helpers::deallocate(
+        pointer, size, this_handler->handler_);
+  }
+
+  template <typename Handler>
+  inline bool asio_handler_is_continuation(
+      redirect_error_handler<Handler>* this_handler)
+  {
+    return asio_handler_cont_helpers::is_continuation(
+          this_handler->handler_);
+  }
+
+  template <typename Function, typename Handler>
+  inline void asio_handler_invoke(Function& function,
+      redirect_error_handler<Handler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+  }
+
+  template <typename Function, typename Handler>
+  inline void asio_handler_invoke(const Function& function,
+      redirect_error_handler<Handler>* this_handler)
+  {
+    asio_handler_invoke_helpers::invoke(
+        function, this_handler->handler_);
+  }
+} // namespace detail
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+template <typename CompletionToken, typename Signature>
+struct handler_type<redirect_error_t<CompletionToken>, Signature>
+{
+  typedef detail::redirect_error_handler<
+    typename handler_type<CompletionToken,
+      Signature>::type> type;
+};
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename CompletionToken, typename R, typename... Args>
+struct handler_type<redirect_error_t<CompletionToken>,
+    R(asio::error_code, Args...)>
+{
+  typedef detail::redirect_error_handler<
+    typename handler_type<CompletionToken,
+      R(Args...)>::type> type;
+};
+
+template <typename CompletionToken, typename R, typename... Args>
+struct handler_type<redirect_error_t<CompletionToken>,
+    R(const asio::error_code&, Args...)>
+{
+  typedef detail::redirect_error_handler<
+    typename handler_type<CompletionToken,
+      R(Args...)>::type> type;
+};
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename CompletionToken, typename R>
+struct handler_type<redirect_error_t<CompletionToken>,
+    R(asio::error_code)>
+{
+  typedef detail::redirect_error_handler<
+    typename handler_type<CompletionToken,
+      R()>::type> type;
+};
+
+template <typename CompletionToken, typename R>
+struct handler_type<redirect_error_t<CompletionToken>,
+    R(const asio::error_code&)>
+{
+  typedef detail::redirect_error_handler<
+    typename handler_type<CompletionToken,
+      R()>::type> type;
+};
+
+#define ASIO_PRIVATE_REDIRECT_ERROR_DEF(n) \
+  template <typename CompletionToken, \
+      typename R, ASIO_VARIADIC_TPARAMS(n)> \
+  struct handler_type<redirect_error_t<CompletionToken>, \
+      R(asio::error_code, ASIO_VARIADIC_TARGS(n))> \
+  { \
+    typedef detail::redirect_error_handler< \
+      typename handler_type<CompletionToken, \
+        R(ASIO_VARIADIC_TARGS(n))>::type> type; \
+  }; \
+  \
+  template <typename CompletionToken, \
+      typename R, ASIO_VARIADIC_TPARAMS(n)> \
+  struct handler_type<redirect_error_t<CompletionToken>, \
+      R(const asio::error_code&, ASIO_VARIADIC_TARGS(n))> \
+  { \
+    typedef detail::redirect_error_handler< \
+      typename handler_type<CompletionToken, \
+        R(ASIO_VARIADIC_TARGS(n))>::type> type; \
+  }; \
+  /**/
+  ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_REDIRECT_ERROR_DEF)
+#undef ASIO_PRIVATE_REDIRECT_ERROR_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename Handler>
+struct async_result<detail::redirect_error_handler<Handler> >
+  : async_result<Handler>
+{
+  explicit async_result(detail::redirect_error_handler<Handler>& h)
+    : async_result<Handler>(h.handler_)
+  {
+  }
+};
+
+template <typename Handler, typename Executor>
+struct associated_executor<detail::redirect_error_handler<Handler>, Executor>
+{
+  typedef typename associated_executor<Handler, Executor>::type type;
+
+  static type get(const detail::redirect_error_handler<Handler>& h,
+      const Executor& ex = Executor()) ASIO_NOEXCEPT
+  {
+    return associated_executor<Handler, Executor>::get(h.handler_, ex);
+  }
+};
+
+template <typename Handler, typename Allocator>
+struct associated_allocator<detail::redirect_error_handler<Handler>, Allocator>
+{
+  typedef typename associated_allocator<Handler, Allocator>::type type;
+
+  static type get(const detail::redirect_error_handler<Handler>& h,
+      const Allocator& a = Allocator()) ASIO_NOEXCEPT
+  {
+    return associated_allocator<Handler, Allocator>::get(h.handler_, a);
+  }
+};
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_REDIRECT_ERROR_HPP
diff --git a/asio/include/asio/redirect_error.hpp b/asio/include/asio/redirect_error.hpp
new file mode 100644
index 0000000..b2da15c
--- /dev/null
+++ b/asio/include/asio/redirect_error.hpp
@@ -0,0 +1,63 @@
+//
+// redirect_error.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_REDIRECT_ERROR_HPP
+#define ASIO_REDIRECT_ERROR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+/// Completion token type used to specify that an error produced by an
+/// asynchronous operation is captured to an error_code variable.
+/**
+ * The redirect_error_t class is used to indicate that any error_code produced
+ * by an asynchronous operation is captured to a specified variable.
+ */
+template <typename CompletionToken>
+class redirect_error_t
+{
+public:
+  /// Constructor. 
+  template <typename T>
+  redirect_error_t(ASIO_MOVE_ARG(T) completion_token, error_code& ec)
+    : token_(ASIO_MOVE_CAST(T)(completion_token)),
+      ec_(ec)
+  {
+  }
+
+//private:
+  CompletionToken token_;
+  error_code& ec_;
+};
+
+/// Create a completion token to capture error_code values to a variable.
+template <typename CompletionToken>
+inline redirect_error_t<typename decay<CompletionToken>::type>
+redirect_error(CompletionToken&& completion_token, error_code& ec)
+{
+  return redirect_error_t<typename decay<CompletionToken>::type>(
+      ASIO_MOVE_CAST(CompletionToken)(completion_token), ec);
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/impl/redirect_error.hpp"
+
+#endif // ASIO_REDIRECT_ERROR_HPP
diff --git a/asio/src/examples/cpp1z/await/chat_server.cpp b/asio/src/examples/cpp1z/await/chat_server.cpp
new file mode 100644
index 0000000..88afb75
--- /dev/null
+++ b/asio/src/examples/cpp1z/await/chat_server.cpp
@@ -0,0 +1,209 @@
+//
+// chat_server.cpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <cstdlib>
+#include <deque>
+#include <iostream>
+#include <list>
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+#include <asio/await.hpp>
+#include <asio/detached.hpp>
+#include <asio/redirect_error.hpp>
+#include <asio/signal_set.hpp>
+#include <asio/ts/networking.hpp>
+
+using asio::ip::tcp;
+
+//----------------------------------------------------------------------
+
+class chat_participant
+{
+public:
+  virtual ~chat_participant() {}
+  virtual void deliver(const std::string& msg) = 0;
+};
+
+typedef std::shared_ptr<chat_participant> chat_participant_ptr;
+
+//----------------------------------------------------------------------
+
+class chat_room
+{
+public:
+  void join(chat_participant_ptr participant)
+  {
+    participants_.insert(participant);
+    for (auto msg: recent_msgs_)
+      participant->deliver(msg);
+  }
+
+  void leave(chat_participant_ptr participant)
+  {
+    participants_.erase(participant);
+  }
+
+  void deliver(const std::string& msg)
+  {
+    recent_msgs_.push_back(msg);
+    while (recent_msgs_.size() > max_recent_msgs)
+      recent_msgs_.pop_front();
+
+    for (auto participant: participants_)
+      participant->deliver(msg);
+  }
+
+private:
+  std::set<chat_participant_ptr> participants_;
+  enum { max_recent_msgs = 100 };
+  std::deque<std::string> recent_msgs_;
+};
+
+//----------------------------------------------------------------------
+
+class chat_session
+  : public chat_participant,
+    public std::enable_shared_from_this<chat_session>
+{
+public:
+  chat_session(tcp::socket socket, chat_room& room)
+    : socket_(std::move(socket)),
+      timer_(socket_.get_executor().context()),
+      room_(room)
+  {
+    timer_.expires_at(std::chrono::steady_clock::time_point::max());
+  }
+
+  void start()
+  {
+    room_.join(shared_from_this());
+
+    asio::spawn(socket_.get_executor(),
+        &chat_session::reader, shared_from_this(), asio::detached);
+
+    asio::spawn(socket_.get_executor(),
+        &chat_session::writer, shared_from_this(), asio::detached);
+  }
+
+  void deliver(const std::string& msg)
+  {
+    write_msgs_.push_back(msg);
+    timer_.cancel_one();
+  }
+
+private:
+  asio::awaitable<void> reader(asio::await_context ctx)
+  {
+    try
+    {
+      for (std::string read_msg;;)
+      {
+        std::size_t n = co_await asio::async_read_until(socket_,
+            asio::dynamic_buffer(read_msg, 1024), "\n", ctx);
+
+        room_.deliver(read_msg.substr(0, n));
+        read_msg.erase(0, n);
+      }
+    }
+    catch (std::exception&)
+    {
+      stop();
+    }
+  }
+
+  asio::awaitable<void> writer(asio::await_context ctx)
+  {
+    try
+    {
+      while (socket_.is_open())
+      {
+        if (write_msgs_.empty())
+        {
+          asio::error_code ec;
+          co_await timer_.async_wait(asio::redirect_error(ctx, ec));
+        }
+        else
+        {
+          co_await asio::async_write(socket_,
+              asio::buffer(write_msgs_.front()), ctx);
+          write_msgs_.pop_front();
+        }
+      }
+    }
+    catch (std::exception&)
+    {
+      stop();
+    }
+  }
+
+  void stop()
+  {
+    room_.leave(shared_from_this());
+    socket_.close();
+    timer_.cancel();
+  }
+
+  tcp::socket socket_;
+  asio::steady_timer timer_;
+  chat_room& room_;
+  std::deque<std::string> write_msgs_;
+};
+
+//----------------------------------------------------------------------
+
+asio::awaitable<void> listener(tcp::acceptor acceptor, asio::await_context ctx)
+{
+  chat_room room;
+
+  for (;;)
+  {
+    std::make_shared<chat_session>(
+        co_await acceptor.async_accept(ctx),
+        room
+      )->start();
+  }
+}
+
+//----------------------------------------------------------------------
+
+int main(int argc, char* argv[])
+{
+  try
+  {
+    if (argc < 2)
+    {
+      std::cerr << "Usage: chat_server <port> [<port> ...]\n";
+      return 1;
+    }
+
+    asio::io_context io_context;
+
+    for (int i = 1; i < argc; ++i)
+    {
+      unsigned short port = std::atoi(argv[i]);
+      asio::spawn(io_context, listener,
+          tcp::acceptor(io_context, {tcp::v4(), port}),
+          asio::detached);
+    }
+
+    asio::signal_set signals(io_context, SIGINT, SIGTERM);
+    signals.async_wait([&](auto, auto){ io_context.stop(); });
+
+    io_context.run();
+  }
+  catch (std::exception& e)
+  {
+    std::cerr << "Exception: " << e.what() << "\n";
+  }
+
+  return 0;
+}