Index: include/std/fstream
===================================================================
--- include/std/fstream	(revision 164549)
+++ include/std/fstream	(working copy)
@@ -125,8 +125,8 @@
        *
        *  NB: _M_reading == true && _M_writing == true is unused.
        */
-      bool                      _M_reading;
-      bool                      _M_writing;
+      bool                      _M_codecvt_always_noconv;
+      bool                      _M_post_overflow;
 
       //@{
       /**
@@ -163,6 +163,18 @@
       const char*		_M_ext_next;
       char*			_M_ext_end;
 
+      bool
+      _M_reading() const
+      {
+	return this->eback() != this->egptr();
+      }
+      
+      bool
+      _M_writing() const
+      {
+	return this->pbase() != this->epptr();
+      }
+      
       /**
        *  Initializes pback buffers, and moves normal buffers to safety.
        *  Assumptions:
Index: include/ext/stdio_filebuf.h
===================================================================
--- include/ext/stdio_filebuf.h	(revision 164549)
+++ include/ext/stdio_filebuf.h	(working copy)
@@ -131,8 +131,6 @@
 	  this->_M_mode = __mode;
 	  this->_M_buf_size = __size;
 	  this->_M_allocate_internal_buffer();
-	  this->_M_reading = false;
-	  this->_M_writing = false;
 	  this->_M_set_buffer(-1);
 	}
     }
@@ -148,8 +146,6 @@
 	  this->_M_mode = __mode;
 	  this->_M_buf_size = __size;
 	  this->_M_allocate_internal_buffer();
-	  this->_M_reading = false;
-	  this->_M_writing = false;
 	  this->_M_set_buffer(-1);
 	}
     }
Index: include/bits/fstream.tcc
===================================================================
--- include/bits/fstream.tcc	(revision 164549)
+++ include/bits/fstream.tcc	(working copy)
@@ -78,15 +78,12 @@
     basic_filebuf<_CharT, _Traits>::
     basic_filebuf() : __streambuf_type(), _M_lock(), _M_file(&_M_lock),
     _M_mode(ios_base::openmode(0)), _M_state_beg(), _M_state_cur(),
-    _M_state_last(), _M_buf(0), _M_buf_size(BUFSIZ),
-    _M_buf_allocated(false), _M_reading(false), _M_writing(false), _M_pback(), 
+    _M_state_last(), _M_buf(0), _M_buf_size(BUFSIZ), _M_buf_allocated(false),
+    _M_codecvt_always_noconv(false), _M_post_overflow(false), _M_pback(), 
     _M_pback_cur_save(0), _M_pback_end_save(0), _M_pback_init(false),
     _M_codecvt(0), _M_ext_buf(0), _M_ext_buf_size(0), _M_ext_next(0),
     _M_ext_end(0)
-    {
-      if (has_facet<__codecvt_type>(this->_M_buf_locale))
-	_M_codecvt = &use_facet<__codecvt_type>(this->_M_buf_locale);
-    }
+    { }
 
   template<typename _CharT, typename _Traits>
     typename basic_filebuf<_CharT, _Traits>::__filebuf_type*
@@ -94,8 +91,10 @@
     open(const char* __s, ios_base::openmode __mode)
     {
       __filebuf_type *__ret = 0;
-      if (!this->is_open())
+      if (!this->is_open() && has_facet<__codecvt_type>(this->getloc()))
 	{
+	  _M_codecvt = &use_facet<__codecvt_type>(this->getloc());
+	  _M_codecvt_always_noconv = _M_codecvt->always_noconv();
 	  _M_file.open(__s, __mode);
 	  if (this->is_open())
 	    {
@@ -103,8 +102,6 @@
 	      _M_mode = __mode;
 
 	      // Setup initial buffer to 'uncommitted' mode.
-	      _M_reading = false;
-	      _M_writing = false;
 	      _M_set_buffer(-1);
 
 	      // Reset to initial state.
@@ -142,8 +139,6 @@
 	    __fb->_M_mode = ios_base::openmode(0);
 	    __fb->_M_pback_init = false;
 	    __fb->_M_destroy_internal_buffer();
-	    __fb->_M_reading = false;
-	    __fb->_M_writing = false;
 	    __fb->_M_set_buffer(-1);
 	    __fb->_M_state_last = __fb->_M_state_cur = __fb->_M_state_beg;
 	  }
@@ -188,10 +183,10 @@
 #if _GLIBCXX_HAVE_DOS_BASED_FILESYSTEM
 	  // About this workaround, see libstdc++/20806.
 	  const bool __testbinary = _M_mode & ios_base::binary;
-	  if (__check_facet(_M_codecvt).encoding() >= 0
+	  if (_M_codecvt->encoding() >= 0
 	      && __testbinary)
 #else
-	  if (__check_facet(_M_codecvt).encoding() >= 0)
+	  if (_M_codecvt->encoding() >= 0)
 #endif
 	    __ret += _M_file.showmanyc() / _M_codecvt->max_length();
 	}
@@ -207,13 +202,12 @@
       const bool __testin = _M_mode & ios_base::in;
       if (__testin)
 	{
-         if (_M_writing)
+         if (_M_writing())
            {
              __ret = overflow();
              if (__ret == traits_type::eof())
                return __ret;
              _M_set_buffer(-1);
-             _M_writing = false;
            }
 	  // Check for pback madness, and if so switch back to the
 	  // normal buffers and jet outta here before expensive
@@ -231,7 +225,7 @@
 	  // Number of internal characters produced.
 	  streamsize __ilen = 0;
 	  codecvt_base::result __r = codecvt_base::ok;
-	  if (__check_facet(_M_codecvt).always_noconv())
+	  if (_M_codecvt_always_noconv)
 	    {
 	      __ilen = _M_file.xsgetn(reinterpret_cast<char*>(this->eback()),
 				      __buflen);
@@ -257,7 +251,7 @@
 
 	      // An imbue in 'read' mode implies first converting the external
 	      // chars already present.
-	      if (_M_reading && this->egptr() == this->eback() && __remainder)
+	      if (_M_reading() && this->egptr() == this->eback() && __remainder)
 		__rlen = 0;
 
 	      // Allocate buffer if necessary and move unconverted
@@ -332,7 +326,6 @@
 	  if (__ilen > 0)
 	    {
 	      _M_set_buffer(__ilen);
-	      _M_reading = true;
 	      __ret = traits_type::to_int_type(*this->gptr());
 	    }
 	  else if (__got_eof)
@@ -341,7 +334,6 @@
 	      // mode, thus allowing an immediate write without an
 	      // intervening seek.
 	      _M_set_buffer(-1);
-	      _M_reading = false;
 	      // However, reaching it while looping on partial means that
 	      // the file has got an incomplete character.
 	      if (__r == codecvt_base::partial)
@@ -355,6 +347,7 @@
 	    __throw_ios_failure(__N("basic_filebuf::underflow "
 				"error reading the file"));
 	}
+      _M_post_overflow = false;
       return __ret;
     }
 
@@ -367,13 +360,12 @@
       const bool __testin = _M_mode & ios_base::in;
       if (__testin)
 	{
-         if (_M_writing)
+         if (_M_writing())
            {
              __ret = overflow();
              if (__ret == traits_type::eof())
                return __ret;
              _M_set_buffer(-1);
-             _M_writing = false;
            }
 	  // Remember whether the pback buffer is active, otherwise below
 	  // we may try to store in it a second char (libstdc++/9761).
@@ -410,7 +402,6 @@
 	  else if (!__testpb)
 	    {
 	      _M_create_pback();
-	      _M_reading = true;
 	      *this->gptr() = traits_type::to_char_type(__i);
 	      __ret = __i;
 	    }
@@ -428,7 +419,7 @@
       const bool __testout = _M_mode & ios_base::out;
       if (__testout)
 	{
-          if (_M_reading)
+          if (_M_reading())
             {
               _M_destroy_pback();
               const int __gptr_off = _M_get_ext_pos(_M_state_last);
@@ -456,11 +447,10 @@
 	    }
 	  else if (_M_buf_size > 1)
 	    {
-	      // Overflow in 'uncommitted' mode: set _M_writing, set
+	      // Overflow in 'uncommitted' mode: create put area, set
 	      // the buffer to the initial 'write' mode, and put __c
 	      // into the buffer.
 	      _M_set_buffer(0);
-	      _M_writing = true;
 	      if (!__testeof)
 		{
 		  *this->pptr() = traits_type::to_char_type(__c);
@@ -474,11 +464,11 @@
 	      char_type __conv = traits_type::to_char_type(__c);
 	      if (__testeof || _M_convert_to_external(&__conv, 1))
 		{
-		  _M_writing = true;
 		  __ret = traits_type::not_eof(__c);
 		}
 	    }
 	}
+      _M_post_overflow = true;
       return __ret;
     }
 
@@ -490,7 +480,7 @@
       // Sizes of external and pending output.
       streamsize __elen;
       streamsize __plen;
-      if (__check_facet(_M_codecvt).always_noconv())
+      if (_M_codecvt_always_noconv)
 	{
 	  __elen = _M_file.xsputn(reinterpret_cast<char*>(__ibuf), __ilen);
 	  __plen = __ilen;
@@ -570,8 +560,8 @@
        const bool __testin = _M_mode & ios_base::in;
        const streamsize __buflen = _M_buf_size > 1 ? _M_buf_size - 1 : 1;
 
-       if (__n > __buflen && __check_facet(_M_codecvt).always_noconv()
-	   && __testin && !_M_writing)
+       if (__n > __buflen && _M_codecvt_always_noconv
+	   && __testin && !_M_writing())
 	 {
 	   // First, copy the chars already present in the buffer.
 	   const streamsize __avail = this->egptr() - this->gptr();
@@ -611,7 +601,6 @@
 	   if (__n == 0)
 	     {
 	       _M_set_buffer(0);
-	       _M_reading = true;
 	     }
 	   else if (__len == 0)
 	     {
@@ -619,7 +608,6 @@
 	       // mode, thus allowing an immediate write without
 	       // an intervening seek.
 	       _M_set_buffer(-1);
-	       _M_reading = false;
 	     }
 	 }
        else
@@ -638,15 +626,14 @@
        // using the buffer.
        streamsize __ret = 0;
        const bool __testout = _M_mode & ios_base::out;
-       if (__check_facet(_M_codecvt).always_noconv()
-	   && __testout && !_M_reading)
+       if (_M_codecvt_always_noconv && __testout && !_M_reading())
 	{
 	  // Measurement would reveal the best choice.
 	  const streamsize __chunk = 1ul << 10;
 	  streamsize __bufavail = this->epptr() - this->pptr();
 
 	  // Don't mistake 'uncommitted' mode buffered with unbuffered.
-	  if (!_M_writing && _M_buf_size > 1)
+	  if (!_M_writing() && _M_buf_size > 1)
 	    __bufavail = _M_buf_size - 1;
 
 	  const streamsize __limit = std::min(__chunk, __bufavail);
@@ -660,7 +647,7 @@
 	      if (__ret == __buffill + __n)
 		{
 		  _M_set_buffer(0);
-		  _M_writing = true;
+		  _M_post_overflow = true;
 		}
 	      if (__ret > __buffill)
 		__ret -= __buffill;
@@ -724,7 +711,7 @@
 	  // In that case, determining the position requires converting the
 	  // put sequence. That doesn't use ext_buf, so requires a flush.
 	  bool __no_movement = __way == ios_base::cur && __off == 0
-	    && (!_M_writing || _M_codecvt->always_noconv());
+	    && (!_M_writing() || _M_codecvt_always_noconv);
 
 	  // Ditch any pback buffers to avoid confusion.
 	  if (!__no_movement)
@@ -737,7 +724,7 @@
 	  // an unshift sequence should have been written at the end.
 	  __state_type __state = _M_state_beg;
 	  off_type __computed_off = __off * __width;
-	  if (_M_reading && __way == ios_base::cur)
+	  if (_M_reading() && __way == ios_base::cur)
 	    {
 	      __state = _M_state_last;
 	      __computed_off += _M_get_ext_pos(__state);
@@ -746,7 +733,7 @@
 	    __ret = _M_seek(__computed_off, __way, __state);
 	  else
 	    {
-	      if (_M_writing)
+	      if (_M_writing())
 		__computed_off = this->pptr() - this->pbase();
 	      
  	      off_type __file_off = _M_file.seekoff(0, ios_base::cur);
@@ -757,6 +744,7 @@
 		}
 	    }
 	}
+      _M_post_overflow = false;
       return __ret;
     }
 
@@ -776,6 +764,7 @@
 	  _M_destroy_pback();
 	  __ret = _M_seek(off_type(__pos), ios_base::beg, __pos.state());
 	}
+      _M_post_overflow = false;
       return __ret;
     }
 
@@ -790,8 +779,6 @@
 	  off_type __file_off = _M_file.seekoff(__off, __way);
 	  if (__file_off != off_type(-1))
 	    {
-	      _M_reading = false;
-	      _M_writing = false;
 	      _M_ext_next = _M_ext_end = _M_ext_buf;
 	      _M_set_buffer(-1);
 	      _M_state_cur = __state;
@@ -807,9 +794,9 @@
   // from eback() correspondence to gptr().
   template<typename _CharT, typename _Traits>
     int basic_filebuf<_CharT, _Traits>::
-    _M_get_ext_pos(__state_type& __state)
+    _M_get_ext_pos(__state_type &__state)
     {
-      if (_M_codecvt->always_noconv())
+      if (_M_codecvt_always_noconv)
         return this->gptr() - this->egptr();
       else
         {
@@ -838,8 +825,7 @@
 	}
 
       // Part two: output unshift sequence.
-      if (_M_writing && !__check_facet(_M_codecvt).always_noconv()
-	  && __testvalid)
+      if (_M_post_overflow && !_M_codecvt_always_noconv && __testvalid)
 	{
 	  // Note: this value is arbitrary, since there is no way to
 	  // get the length of the unshift sequence from codecvt,
@@ -906,54 +892,34 @@
     basic_filebuf<_CharT, _Traits>::
     imbue(const locale& __loc)
     {
-      bool __testvalid = true;
-
-      const __codecvt_type* _M_codecvt_tmp = 0;
-      if (__builtin_expect(has_facet<__codecvt_type>(__loc), true))
-	_M_codecvt_tmp = &use_facet<__codecvt_type>(__loc);
-
       if (this->is_open())
 	{
-	  // encoding() == -1 is ok only at the beginning.
-	  if ((_M_reading || _M_writing)
-	      && __check_facet(_M_codecvt).encoding() == -1)
-	    __testvalid = false;
-	  else
-	    {
-	      if (_M_reading)
-		{
-		  if (__check_facet(_M_codecvt).always_noconv())
-		    {
-		      if (_M_codecvt_tmp
-			  && !__check_facet(_M_codecvt_tmp).always_noconv())
-			__testvalid = this->seekoff(0, ios_base::cur, _M_mode)
-			              != pos_type(off_type(-1));
-		    }
-		  else
-		    {
-		      // External position corresponding to gptr().
-		      _M_ext_next = _M_ext_buf
-			+ _M_codecvt->length(_M_state_last, _M_ext_buf, _M_ext_next,
-					     this->gptr() - this->eback());
-		      const streamsize __remainder = _M_ext_end - _M_ext_next;
-		      if (__remainder)
-			__builtin_memmove(_M_ext_buf, _M_ext_next, __remainder);
-
-		      _M_ext_next = _M_ext_buf;
-		      _M_ext_end = _M_ext_buf + __remainder;
-		      _M_set_buffer(-1);
-		      _M_state_last = _M_state_cur = _M_state_beg;
-		    }
-		}
-	      else if (_M_writing && (__testvalid = _M_terminate_output()))
-		_M_set_buffer(-1);
-	    }
+	  /*if (_M_codecvt->encoding() == -1 // 27.8.1.4/17
+	      && typeid (*_M_codecvt) != typeid (__new_codecvt_tmp)
+	      && seekoff(0,ios_base::cur) != pos_type(off_type(0)))
+	    __throw_ios_failure(__N("basic_filebuf::imbue "
+				    "cannot leave stateful cvt midstream"));
+	  
+	  The above is very high-minded, but 27.8.1.4/19 mentions that imbue
+	  is intended to reconstruct the entire file into the new encoding.
+	  Hence not working midstream: no pos_type value besides pos_type()
+	  can be translated across encodings. This leaves a dilemma: either
+	  convert the file, which really isn't our job, or disallow imbue
+	  for any non-empty file. Disallowing some subset when encoding == -1
+	  doesn't make sense; that has no more potential to corrupt the file
+	  than any other case. The least surprising, least restrictive
+	  behavior is to leave the user responsible for shooting his own foot.
+	  
+	  The most we can do is flush and unshift, for determinism.
+	  */
+
+	  if (_M_writing() && !_M_terminate_output()
+	      || _M_reading() && overflow() == traits_type::eof())
+	    __throw_ios_failure("basic_filebuf::imbue could not flush");
+	  
+	  _M_codecvt = &use_facet<__codecvt_type>(__loc);
+	  _M_codecvt_always_noconv = _M_codecvt->always_noconv();
 	}
-
-      if (__testvalid)
-	_M_codecvt = _M_codecvt_tmp;
-      else
-	_M_codecvt = 0;
     }
 
   // Inhibit implicit instantiations for required instantiations,
Index: testsuite/27_io/basic_filebuf/seekoff/wchar_t/12790-2.cc
===================================================================
--- testsuite/27_io/basic_filebuf/seekoff/wchar_t/12790-2.cc	(revision 164549)
+++ testsuite/27_io/basic_filebuf/seekoff/wchar_t/12790-2.cc	(working copy)
@@ -68,7 +68,7 @@
   fb.sputc(L'a');
 
   VERIFY( !cvt->unshift_called );
-  fb.pubseekoff(0, ios_base::cur);
+  fb.pubseekoff(0, ios_base::beg);
   VERIFY( cvt->unshift_called );
 }
 
Index: testsuite/27_io/basic_filebuf/seekoff/char/12790-2.cc
===================================================================
--- testsuite/27_io/basic_filebuf/seekoff/char/12790-2.cc	(revision 164549)
+++ testsuite/27_io/basic_filebuf/seekoff/char/12790-2.cc	(working copy)
@@ -70,7 +70,7 @@
   fb.sputc('a');
 
   VERIFY( !cvt->unshift_called );
-  fb.pubseekoff(0, ios_base::cur);
+  fb.pubseekoff(0, ios_base::beg);
   VERIFY( cvt->unshift_called );
 }
 
