vsapsai added inline comments.

================
Comment at: clang/lib/Frontend/CompilerInstance.cpp:1063
+        << ModuleName;
+    return ImportingInstance.getFrontendOpts().AllowPCMWithCompilerErrors;
+  }
----------------
bnbarham wrote:
> bnbarham wrote:
> > vsapsai wrote:
> > > Can we get in infinite loop with `AllowPCMWithCompilerErrors = true`? 
> > > Specifically, I'm thinking about the scenario
> > > 
> > > 1. `compileModuleAndReadAST` obtains a file lock and calls `compileModule`
> > > 2. `compileModule` calls `compileModuleImpl`
> > > 3. Module is finalized but `AllowPCMWithCompilerErrors` is true, so 
> > > `compileModuleImpl` returns true
> > > 4. `compileModule` returns true
> > > 5. `compileModuleAndReadAST` tries to read AST because compilation was 
> > > successful
> > > 6. AST is out of date, so `compileModuleAndReadAST` decides to try again, 
> > > goto 1
> > > 
> > > Haven't tried to reproduce it locally but even if this scenario is 
> > > impossible, a corresponding test case can be useful.
> > Nice catch, that does seem likely - I'll see if I can add a test for this.
> It doesn't end up causing an infinite recursion as `false` will end up being 
> returned from `compileModuleAndReadAST`, but in that case there's no point 
> returning `true` from `compileModuleImpl` in the first place so I've changed 
> it anyway. Have also added that as a test case, just to make sure.
Thanks for investigating it and adding a test case.

And appreciate that the error message mentions the module name. It is so hard 
to work with errors like "cannot rebuild this module".


================
Comment at: clang/lib/Serialization/ASTReader.cpp:2923
           if (!BuildDir || *BuildDir != M->Directory) {
-            if ((ClientLoadCapabilities & ARR_OutOfDate) == 0)
+            if (diagnoseOutOfDate(F.FileName, ClientLoadCapabilities))
               Diag(diag::err_imported_module_relocated)
----------------
bnbarham wrote:
> bnbarham wrote:
> > vsapsai wrote:
> > > I'm thinking if in case of finalized modules diagnostic messages are good 
> > > enough. One concern is it won't be clear why a module wasn't rebuilt. It 
> > > can be already confusing for precompiled headers and I'm afraid we won't 
> > > be able to detect `isPCMFinal` code path without a debugger. Though I 
> > > don't know how bad that would be in practice.
> > > 
> > > Another concern is that retrying a compilation should succeed as for a 
> > > new process we have a new InMemoryModuleCache and `isPCMFinal` should 
> > > return false. So we might have non-deterministic behavior and some of the 
> > > valid error messages can seem to be non-deterministic and not reliable. I 
> > > was thinking about adding a note in case we are dealing with `isPCMFinal` 
> > > to distinguish these cases but not sure it is a good idea.
> > > I'm thinking if in case of finalized modules diagnostic messages are good 
> > > enough. One concern is it won't be clear why a module wasn't rebuilt. It 
> > > can be already confusing for precompiled headers and I'm afraid we won't 
> > > be able to detect `isPCMFinal` code path without a debugger. Though I 
> > > don't know how bad that would be in practice.
> > 
> > The error messages will mention a module in the module cache, which would 
> > be the main way to tell. We could add a note here as you suggest below, but 
> > I'm not quite sure what it would say... something about there being two 
> > modules with the same name?
> > 
> > > Another concern is that retrying a compilation should succeed as for a 
> > > new process we have a new InMemoryModuleCache and `isPCMFinal` should 
> > > return false. So we might have non-deterministic behavior and some of the 
> > > valid error messages can seem to be non-deterministic and not reliable. I 
> > > was thinking about adding a note in case we are dealing with `isPCMFinal` 
> > > to distinguish these cases but not sure it is a good idea.
> > 
> > The errors should be deterministic I believe. If one process has the issue 
> > then a new one will have the issue as well. For what it's worth, I don't 
> > think these crashes are possible from the clang frontend. They require 
> > messing around with search paths such that between two compilations in the 
> > same process, different modules are found.
> I've added an extra note "this is generally caused by modules with the same 
> name found in multiple paths". So the diagnostics would now be:
> ```
> /.../test.m:2:10: fatal error: module 'M' was built in directory 
> '/.../frameworks/M.framework' but now resides in directory 
> 'frameworks2/M.framework'
>         @import Top;
>          ^
> /.../test.m:2:10: note: imported by module 'Top' in 
> '/path/to/module/cache/LGSY9KSYAKN1/Top-1MZE9QJ1AHENQ.pcm
> /.../test.m:2:10: note: this is generally caused by modules with the same 
> name found in multiple paths
> ```
> 
> I was thinking of mentioning the finalized module, but that's really just a 
> side effect of the error that should have already been output (ie. `module 
> 'M' was built in...` in this case). So the existence of this note should help 
> point users to the problem + make which path caused the error obvious when 
> looking at the code.
I like the note. Think it gives a good hint at what's wrong and we don't need 
to improve it further now.

> The errors should be deterministic I believe. If one process has the issue 
> then a new one will have the issue as well. For what it's worth, I don't 
> think these crashes are possible from the clang frontend. They require 
> messing around with search paths such that between two compilations in the 
> same process, different modules are found.

Thanks for the explanation. I was thinking about triggering the error not 
through API but through clang frontend. But I see that through API the error 
should be deterministic.


================
Comment at: clang/lib/Serialization/ASTReader.cpp:5929
 
+bool ASTReader::diagnoseOutOfDate(StringRef ModuleFileName,
+                                  unsigned int ClientLoadCapabilities) {
----------------
bnbarham wrote:
> bnbarham wrote:
> > vsapsai wrote:
> > > Based on the rest of the code in clang, the expectation for `diagnose...` 
> > > methods is to emit diagnostic in some cases. Personally, I'm often 
> > > confused what true/false means for these methods, so I'm thinking about 
> > > renaming the method to something like isRecoverableOutOfDateModule, 
> > > canRecoverOutOfDateModule or some such. Feel free to pick a name you 
> > > believe is appropriate, mine are just examples.
> > Fair enough, `canRecoverOutOfDateModule` sounds reasonable to me. Or maybe 
> > `canRecoverFromOutOfDate`?
> I went with the latter.
I think with the current naming we need to flip the conditions to opposite. 
Currently,

```lang=c++
  return !(ClientLoadCapabilities & ARR_OutOfDate) ||
         getModuleManager().getModuleCache().isPCMFinal(ModuleFileName);
```

corresponds to `cannotRecoverFromOutOfDate`. But to avoid double negations it 
is better to have `canRecoverFromOutOfDate` (with `(ClientLoadCapabilities & 
ARR_OutOfDate) && !isPCMFinal(ModuleFileName)`) and call it as 
`!canRecoverFromOutOfDate` when necessary.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D105328

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to