[PATCH] D87989: [Flang][Driver] Add InputOutputTest frontend action with new -test-IO flag

Andrzej Warzynski via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Tue Sep 22 10:19:54 PDT 2020


awarzynski added a comment.

@CarolineConcatto , thank you for this patch! It implements some really important functionality and IMO the overall structure is solid.

I've left quite a few comments, but mostly nits and suggestions for more detailed comments. There's a few, but it's a relatively big patch :)

One suggestion - IMO this patch first and foremost creates the scaffolding for writing frontend actions. The `test-IO` flag is only really there to facilitate testing. Perhaps it's worth updating the commit message to reflect that? I would definitely like to see a bit more emphasis on the fact that this patch introduces the necessary APIs for reading and writing files. For me that's the key functionality here.

Also, I tested this patch and currently `-test-IO` is listed together with other `clang` options (check `clang --help-hidden`). Please, could you fix that?



================
Comment at: clang/include/clang/Driver/Options.td:3514
+//===----------------------------------------------------------------------===//
+def TEST_IO : Flag<["-"], "test-IO">, Flags<[HelpHidden, FlangOption, FC1Option]>,Group<Action_Group>,
+HelpText<"Only run the InputOutputTest action">;
----------------
I think that `test-io` would be more consistent with other options in the file.


================
Comment at: clang/include/clang/Driver/Options.td:3515
+def TEST_IO : Flag<["-"], "test-IO">, Flags<[HelpHidden, FlangOption, FC1Option]>,Group<Action_Group>,
+HelpText<"Only run the InputOutputTest action">;
+
----------------
I would help to make this a bit more specific. What about: `Run the InputOuputTest action. Use for development and testing only`?


================
Comment at: clang/lib/Driver/ToolChains/Flang.cpp:39-40
   } else if (isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) {
+    CmdArgs.push_back("-triple");
+    CmdArgs.push_back(Args.MakeArgString(TripleStr));
     if (JA.getType() == types::TY_Nothing) {
----------------
It would be helpful to have a note that explains this change. Perhaps something like this:

```
// TODO: Note that eventually all actions will require a triple (e.g. `-triple aarch64-unknown-linux-gnu`). However, `-triple` is currently not supported by `flang-new -fc1`, so we only add it to actions that we don't support/execute just yet. 
```

Probably above line 33. What do you think?


================
Comment at: clang/lib/Driver/Types.cpp:329
   if (Driver.CCCIsCPP() || DAL.getLastArg(options::OPT_E) ||
+      DAL.getLastArg(options::OPT_TEST_IO) ||
       DAL.getLastArg(options::OPT__SLASH_EP) ||
----------------
This should probably be the last option here (as it's the latest to be added). Also, worth adding a comment about, e.g.:
```
-test-io is used by Flang to run InputOutputTest action
```


================
Comment at: flang/include/flang/Frontend/CompilerInstance.h:26
 
+  /// The Fortran  file  manager.
+  std::shared_ptr<Fortran::parser::AllSources> allSources_;
----------------
[nit] Forrtran or Flang?


================
Comment at: flang/include/flang/Frontend/CompilerInstance.h:33
+  /// Holds the name of the output file.
+  /// Helps to go through the list when working with the outputFiles_
+  struct OutputFile {
----------------
[nit] 'the outputFiles_' -> 'outputFiles_'


================
Comment at: flang/include/flang/Frontend/CompilerInstance.h:40-42
+  /// If the output doesn't support seeking (terminal, pipe), we switch
+  /// the stream to a buffer_ostream. These are the buffer and the original
+  /// stream.
----------------
[nit] 
```
/// If the output doesn't support seeking (terminal, pipe), we switch
/// the stream to a buffer_ostream. These are the buffer and the original
/// stream.
```
vvv
```
/// Output stream that doesn't support seeking (e.g. terminal, pipe). This stream is normally wrapped
/// in buffer_ostream before being passed to users (e.g. via CreateOutputFile).
```


================
Comment at: flang/include/flang/Frontend/CompilerInstance.h:48
+
+  /// Force an output buffer.
+  std::unique_ptr<llvm::raw_pwrite_stream> outputStream_;
----------------
I think that:
```
This field holds the output stream provided by the user. Normally, users of CompilerInstance will call CreateOutputFile to obtain/create an output stream. If they want to provide their own output stream, this field will facilitate this. It is optional and will normally be just a nullptr.
```
would be a bit more informative :)


================
Comment at: flang/include/flang/Frontend/CompilerInstance.h:65
 
+  /// setInvocation - Replace the current invocation.
+  void SetInvocation(std::shared_ptr<CompilerInvocation> value);
----------------
[nit] Delete


================
Comment at: flang/include/flang/Frontend/CompilerInstance.h:68
+
+  /// Return the current source manager.
+  Fortran::parser::AllSources &GetAllSources() const { return *allSources_; }
----------------
[nit] There is no source manager here.

It's probably worth decorating everything related to `AllSources` with:
```
/// }
/// @name File manager
/// {
```


================
Comment at: flang/include/flang/Frontend/CompilerInstance.h:73
+
+  /// @name High-Level Operations
+  /// {
----------------
Missing `/// }`


================
Comment at: flang/include/flang/Frontend/CompilerInstance.h:76
+
+  /// ExecuteAction - Execute the provided action against the compiler's
+  /// CompilerInvocation object.
----------------
[nit] No need to repeat the name of the method/member variable in comments. Same for the rest of the patch.


================
Comment at: flang/include/flang/Frontend/CompilerInstance.h:146-147
+
+  /// Has a function to create a new output file and add it to the list of
+  /// tracked output files.
+  ///
----------------
Remove `Has a`? Also, could you expand and clarify the differences between this method and the one below? Ta!


================
Comment at: flang/include/flang/Frontend/CompilerInstance.h:158
+  /// \param error [out] - On failure, the error.
+  /// \param extension - The extension to use for derived output names.
+  /// \param binary - The mode to open the file in.
----------------
This argument is after `binary`


================
Comment at: flang/include/flang/Frontend/CompilerInstance.h:164
+  CreateOutputFile(llvm::StringRef outputPath, std::error_code &error,
+                   bool binary, llvm::StringRef inFile,
+                   llvm::StringRef extension, std::string *resultPathName);
----------------
This argument is not documented.


================
Comment at: flang/include/flang/Frontend/CompilerInstance.h:171-177
+  // OutputStream is private and its contenct cannot be checked outside
+  // CompilerInstance.
+  bool NullOutputStream() {
+    if (outputStream_ == nullptr)
+      return true;
+    return false;
+  }
----------------
[nit] I think that the comment is redundant - this is clear from the implementation and it is a fairly standard C++ idiom (e.g. accessors).

It's a good practice to use proper questions to name functions like this one, e.g. `IsOutputStreamNull`. Then, both possible return values answer this question. Sorry, I couldn't find a link that would document this.

Also, this would be simpler, yet semantically equivalent:
```
 bool IsOutputStreamNull() {return (outputStream_ == nullptr);}
```


================
Comment at: flang/include/flang/Frontend/FrontendAction.h:85
+
+  /// Set the source manager's main input file, and run the action.
+  llvm::Error Execute();
----------------
AFAIK, there is no source manager - only file manager.


================
Comment at: flang/include/flang/Frontend/FrontendOptions.h:19-21
+  // This is temporary solution
+  // Avoids Action = PrintPreprocessedInput as option 0
+  DummyAction = 0,
----------------
I recommend that this is replaced with:
```
InvalidAction = 0,
```
I think that this requires no comments.


================
Comment at: flang/include/flang/Frontend/FrontendOptions.h:111
+  const llvm::MemoryBuffer *GetBuffer() const {
+    assert(IsBuffer());
+    return buffer_;
----------------
Add message, e.g.
```
assert(IsBuffer() && "Requested buffer_, but it is empty!");
```


================
Comment at: flang/lib/Frontend/CompilerInstance.cpp:26
+CompilerInstance::~CompilerInstance() {
+  assert(OutputFiles.empty() && "Still output files in flight?");
+}
----------------
`outputFiles_`?


================
Comment at: flang/lib/Frontend/CompilerInstance.cpp:94-100
+  // Flushes the stream
+  if (!binary || os->supportsSeeking())
+    return std::move(os);
+  auto b = std::make_unique<llvm::buffer_ostream>(*os);
+  assert(!nonSeekStream_);
+  nonSeekStream_ = std::move(os);
+
----------------
The stream is not flushed until it's destructor is called. This happens elsewhere. Here we just return the stream corresponding to the output file.

Since there's a distinction between seekable and non-seekable streams, I'd be tempted to split this as follows:

```  
// Return the stream corresponding to the output file. For non-seekable streams, wrap it in llvm::buffer_ostream first.
  if (!binary || os->supportsSeeking())
    return std::move(os);
  
  assert(!nonSeekStream_ && "The non-seek stream has already been set!");
  auto b = std::make_unique<llvm::buffer_ostream>(*os);
  nonSeekStream_ = std::move(os);
  return std::move(b);
```


================
Comment at: flang/lib/Frontend/FrontendActions.cpp:19
+
+  // Get the name of the file from FrontendInputFile current
+  std::string path{GetCurrentFileOrBufferName()};
----------------
[nit] Get the name of the current file from FrontendInputFile


================
Comment at: flang/test/Flang-Driver/driver-help-hidden.f90:7
+! RUN: %flang-new --help-hidden 2>&1 | FileCheck %s
+! RUN: not %flang-new  -help-hidden 2>&1 | FileCheck %s --check-prefix=ERROR
+
----------------
[nit] Both `--check-prefix=ERROR` and `--check-prefix=ERROR-HIDDEN` check the `help-hidden` flang`. Perhaps `--check-prefix=ERROR-FLANG-NEW` and `--check-prefix=ERROR-FLANG-NEW-FC1` would make the difference between the two cases more obvious?


================
Comment at: flang/test/Flang-Driver/driver-help-hidden.f90:27
+!-------------------------------------------------------------
+! EXPECTED OUTPUT FOR FLANG FRONTEND DRIVER (flang-new -fc1)
+!-------------------------------------------------------------
----------------
This is the expected error for both `flang-new` (compiler driver) and `flang-new -fc1` (the frontend driver).


================
Comment at: flang/test/Flang-Driver/emit-obj.f90:2
 ! RUN: not %flang-new  %s 2>&1 | FileCheck %s --check-prefix=ERROR-IMPLICIT
-! RUN: not %flang-new  -emit-obj %s 2>&1 | FileCheck %s --check-prefix=ERROR-EXPLICIT
 ! RUN: not %flang-new  -fc1 -emit-obj %s 2>&1 | FileCheck %s --check-prefix=ERROR-FC1
----------------
Why is this line deleted? `flang-new -emit-obj` should still fail, right?


================
Comment at: flang/test/Flang-Driver/emit-obj.f90:12
 ! ERROR-IMPLICIT: error: unknown argument: '-emit-obj'
-! ERROR-IMPLICIT: error: unknown argument: '-o'
-
-! ERROR-EXPLICIT: error: unknown argument: '-o'
+! ERROR-IMPLICIT-NOT: error: unknown argument: '-o'
 
----------------
I'd be tempted just to delete this line - we have tests elsewhere to show that `-o` is indeed supported. 


================
Comment at: flang/test/Frontend/multiple-input-files.f90:1
+! RUN: rm -rf %S/multiple-input-files.txt  %S/Inputs/empty-file.txt
+
----------------
I think that this test will be much more interesting and useful if `empty-file.f90` is not empty :)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D87989/new/

https://reviews.llvm.org/D87989



More information about the cfe-commits mailing list