[Bug libstdc++/106932] New: Incorrect behavior of std::filesystem::copy() with overwrite_existing or update_existing options
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106932 Bug ID: 106932 Summary: Incorrect behavior of std::filesystem::copy() with overwrite_existing or update_existing options Product: gcc Version: 11.3.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: thomas.allen at intel dot com Target Milestone: --- When using std::filesystem::copy_options::overwrite_existing or std::filesystem::copy_options::update_existing as part of a call to std::filesystem::copy(), no destination directory is created, and the source directory is not copied. In addition, no exception is thrown. If neither of these options are specified, the behavior is as expected, creating the destination directory and copying all regular files into it. This appears to be contrary to bullet 4.7.4 in Section 29.11.14.3 of the C++20 spec, where for regular files in a source directory, the effect should be equivalent to passing any options through to a copy_file() call on each file. This bug occurs on SUSE Linux Enterprise Server 12 SP5, running on an Intel Xeon Gold 6136 CPU. Additionally, testing with GCC 10.2.0 and 12.2.0 shows the same issue. The build configuration options used with GCC 11.3.0 specifically were: /nfs/orto/proj/tapeout/cit_rep/ImagingToolsSupport/v2/bootstrap/build/sles12/gcc920/gcc/11.3.0/default/extract/gcc-11.3.0/configure --prefix=/nfs/orto/proj/tapeout/cit_rep/ImagingToolsSupport/v2/bootstrap/install/sles12/gcc920/gcc/11.3.0/default --with-specs='%{!static:%x{-rpath=/nfs/orto/proj/tapeout/cit_rep/ImagingToolsSupport/v2/bootstrap/install/sles12/gcc920/gcc/11.3.0/default/lib64:/nfs/orto/proj/tapeout/cit_rep/ImagingToolsSupport/v2/bootstrap/install/sles12/gcc920/gcc/11.3.0/default/lib}}' --enable-lto The command line which triggers this bug is: g++ -std=c++20 -Wall -o dir_copy_test dir_copy_test.cpp No errors or warnings are emitted by the compiler, and the source directory for the test case is identical in structure to the one shown in the Notes section at https://en.cppreference.com/w/cpp/filesystem/copy, i.e. copy_test/ `-- source |-- file1 |-- file3 `-- subdir `-- file2 To produce the issue: cd copy_test dir_copy_test source dest The preprocessor output for the test code is attached.
[Bug libstdc++/106932] Incorrect behavior of std::filesystem::copy() with overwrite_existing or update_existing options
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106932 --- Comment #1 from Tom Allen --- Created attachment 53573 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=53573&action=edit Preprocessor output for minimal testcase reproducing this issue.
[Bug libstdc++/106932] Incorrect behavior of std::filesystem::copy() with overwrite_existing or update_existing options
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106932 --- Comment #4 from Tom Allen --- (In reply to Jonathan Wakely from comment #2) > I think this is the correct behaviour according to the standard. > > Where f is status("source") and t is status("dest"). > > Effects are then as follows: > > - If f.type() or t.type() is an implementation-defined file type ... > > [they're not] > > - Otherwise, an error is reported as specified in 31.12.5 if: > > [list of conditions that are not true] > > - Otherwise, if is_symlink(f), then: > > [it's not] > > - Otherwise, if is_regular_file(f), then: > > [it's not] > > - Otherwise, if > is_directory(f) && > (options & copy_options::create_symlinks) != copy_options::none > > [create_symlinks is not set in the options] > > - Otherwise, if > is_directory(f) && > ((options & copy_options::recursive) != copy_options::none || > options == copy_options::none) > > [this is the case we want to hit, but the condition is false because > recursive is not set and options != none] > > - Otherwise, for the signature with argument ec, ec.clear(). > > [You didn't pass an erroc_code] > > - Otherwise, no effects. > > [Bingo] > > So you need to use copy_options::recursive to get the effects you want. If this is the case, then when I have subdirectories which I explicitly do not want to copy, but files at the same level in the source directory which I do want to overwrite in their destinations, there is no way to perform the operation unless I manually iterate and check file types, then call copy_file(). That seems like a strange asymmetry compared to the recursive call.
[Bug libstdc++/106932] Incorrect behavior of std::filesystem::copy() with overwrite_existing or update_existing options
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106932 --- Comment #6 from Tom Allen --- (In reply to Jonathan Wakely from comment #5) > (In reply to Tom Allen from comment #4) > > If this is the case, then when I have subdirectories which I explicitly do > > not want to copy, but files at the same level in the source directory which > > I do want to overwrite in their destinations, there is no way to perform the > > operation unless I manually iterate and check file types, then call > > copy_file(). > > I don't think that's quite true. You can still use filesystem::copy, you > just need to use copy_options specific to the file type. So iterate over the > directory contents and for directories, call filesystem::copy with no > arguments, and for files, call filesystem::copy with update_existing / > overwrite_existing. > > > That seems like a strange asymmetry compared to the recursive > > call. > > For a recursive call, passing copy_options that only make sense for files is > useful, because there could be files somewhere in a sub-dir that you want to > copy. Passing those when copying just a directory, without recursing, isn't > useful. > > For a shallow, non-recursive copy, I think it makes sense that you would > have to call copy for each file individually, and if you're already doing > that, it's not such a stretch to use arguments specific to the file type. > > In any case, that's what the standard says, so it's not a GCC bug. > > If you think this is a defect in the standard then report it to the > committee instead: > https://cplusplus.github.io/LWG/lwg-active.html#submit_issue In this case, would it be possible to add a warning to the compiler for this usage? Even with -Wall -Wextra it's silent, and since it functions as a no-op, it's somewhat confusing to track down.