PR libstdc++/89117 fix path::replace_extension("") case
authorJonathan Wakely <jwakely@redhat.com>
Wed, 30 Jan 2019 23:18:22 +0000 (23:18 +0000)
committerJonathan Wakely <redi@gcc.gnu.org>
Wed, 30 Jan 2019 23:18:22 +0000 (23:18 +0000)
Previously the operator+=(extension) call would have re-parsed the path
and recreated the components with the right extension. Since optimising
it to not re-parse the whole string, we need to actually remove the
extension from the final filename before appending anything to it, and
append the dot to that final component too.

PR libstdc++/89117
* src/c++17/fs_path.cc (path::replace_extension): Erase extension from
final component as well as from _M_pathname. Append the dot using
operator+= instead of only to _M_pathname.
(path::_M_find_extension): Reformat slightly.
* testsuite/27_io/filesystem/path/modifiers/replace_extension.cc:
Add more test cases.

From-SVN: r268406

libstdc++-v3/ChangeLog
libstdc++-v3/src/c++17/fs_path.cc
libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/replace_extension.cc

index f30fedf2948547209e8224052595f1881049c8a4..36fcab95d7bc99ab7f699b060449de57b3c64ab4 100644 (file)
@@ -1,3 +1,13 @@
+2019-01-30  Jonathan Wakely  <jwakely@redhat.com>
+
+       PR libstdc++/89117
+       * src/c++17/fs_path.cc (path::replace_extension): Erase extension from
+       final component as well as from _M_pathname. Append the dot using
+       operator+= instead of only to _M_pathname.
+       (path::_M_find_extension): Reformat slightly.
+       * testsuite/27_io/filesystem/path/modifiers/replace_extension.cc:
+       Add more test cases.
+
 2019-01-30  Ulrich Drepper  <drepper@redhat.com>
 
        * doc/xml/manual/status_cxx2020.xml: Update P0600 entry.
index 34de52f3a0ffa23f4b4543e75ac43d3e9d30b6d7..db6a1cb29d8d367d2021f21ca9f5dc086716d23e 100644 (file)
@@ -1258,17 +1258,16 @@ path::replace_extension(const path& replacement)
        _M_pathname.erase(ext.second);
       else
        {
-         const auto& back = _M_cmpts.back();
-         if (ext.first != &back._M_pathname)
-           _GLIBCXX_THROW_OR_ABORT(
-               std::logic_error("path::replace_extension failed"));
+         auto& back = _M_cmpts.back();
+         __glibcxx_assert( ext.first == &back._M_pathname );
+         back._M_pathname.erase(ext.second);
          _M_pathname.erase(back._M_pos + ext.second);
        }
     }
    // If replacement is not empty and does not begin with a dot character,
    // a dot character is appended
   if (!replacement.empty() && replacement.native()[0] != dot)
-    _M_pathname += dot;
+    operator+=(".");
   operator+=(replacement);
   return *this;
 }
@@ -1803,8 +1802,9 @@ path::_M_find_extension() const
        {
          if (sz <= 2 && (*s)[0] == dot)
            return { s, string_type::npos };
-         const auto pos = s->rfind(dot);
-         return { s, pos ? pos : string_type::npos };
+         if (const auto pos = s->rfind(dot))
+           return { s , pos };
+         return { s, string_type::npos };
        }
     }
   return {};
index df4b77aa116a4042431cf2b6f7c4723cea5cefa4..98f2e6e4c4179e507206c0daeb57754f112a09e4 100644 (file)
@@ -33,6 +33,15 @@ test01()
   compare_paths( path("/foo.txt").replace_extension("cpp"), "/foo.cpp" );
   compare_paths( path("/foo.txt").replace_extension(".cpp"), "/foo.cpp" );
   compare_paths( path("/").replace_extension("bar"), "/.bar" );
+  compare_paths( path("/").replace_extension(".bar"), "/.bar" );
+  compare_paths( path("/dir/").replace_extension("bar"), "/dir/.bar" );
+  compare_paths( path("dir/foo").replace_extension("bar"), "dir/foo.bar" );
+
+  // PR 89117:
+  compare_paths( path("/foo.txt").replace_extension(), "/foo" );
+  compare_paths( path("foo.txt").replace_extension(), "foo" );
+  compare_paths( path("/foo").replace_extension(), "/foo" );
+  compare_paths( path("foo").replace_extension(), "foo" );
 }
 
 void