iains added a comment.

@rsmith, @ChuanqiXu apologies for the multiple revisions, this has turned out 
to be much more involved than I imagined from the standard's text.

In D126694#3629254 <https://reviews.llvm.org/D126694#3629254>, @ChuanqiXu wrote:

> In D126694#3629251 <https://reviews.llvm.org/D126694#3629251>, @iains wrote:
>
>> In D126694#3629094 <https://reviews.llvm.org/D126694#3629094>, @ChuanqiXu 
>> wrote:
>>
>>> BTW, after I applied the patch, the compiler crashes at 
>>> https://github.com/ChuanqiXu9/stdmodules.
>>
>> That link points to a project - is there (say) a gist of the crash 
>> information?
>
> Here is the crash log:

this code now compiles without error,



================
Comment at: clang/include/clang/AST/DeclBase.h:624
   bool isModulePrivate() const {
     return getModuleOwnershipKind() == ModuleOwnershipKind::ModulePrivate;
   }
----------------
iains wrote:
> ChuanqiXu wrote:
> > According to the opinion from @rsmith, the discarded declaration is private 
> > too.
> I guess you mean `>=`  ... however Discardable is a stronger constraint than 
> Private 
> 
> If a decl remains marked Discardable (after the processing to determine 
> reachable ones) that means it is both unreachable and invisible.
> So it must not participate in any processing (with the one exception of 
> diagnostic output).  I would be concerned that the change you suggest above 
> could cause a  Discardable decl to be considered in merging  or lookup and we 
> would then need (maybe a lot) of logic like:
> 
> ```
>  if (D->isModulePrivate() && !D->isModuleDiscardable())
>     ...
> ```
> 
> I will take a look on the next iteration.
> 
I did try this and there are a number of regressions - when I looked into these 
there is some interaction with the changes made in D113545, so I think we 
should make these changes in a follow-one patch to avoid having two purposes in 
this one.


================
Comment at: clang/include/clang/Sema/Sema.h:2275-2276
 
+  llvm::SmallPtrSet<const Decl *, 32> SeenDecls;
+  llvm::SmallPtrSet<const clang::Type *, 32> SeenTypes;
+
----------------
rsmith wrote:
> These names seem too general to live directly in `Sema`.
(revised we only need to track the type pointers)

On the basis that the name is poor, for its intended purpose, I revised. 


================
Comment at: clang/include/clang/Sema/Sema.h:2273
+  void HandleGMFReachability(Decl *D) {
+    if (D->isModuleUnreachable() && isCurrentModulePurview()) {
+      
D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ReachableWhenImported);
----------------
ChuanqiXu wrote:
> iains wrote:
> > ChuanqiXu wrote:
> > > I feel better if we would check if D lives in GMF. (We need to insert a 
> > > check in isDiscardedInGlobalModuleFragment)
> > If the consensus is to add an extra test, OK.
> > 
> > However, as above, specifically to avoid making more and more tests in code 
> > that is executed very frequently - as the design currently stands, the only 
> > place that  `ModuleUnreachable` is set is in the GMF.
> Yeah, my opinion is the same as above. Although it is the design, it is more 
> semantically clear and robust to add a additional check. I am just afraid it 
> would confuse and block other readers or contributors.
this has now been revised and a check is applied before any change is made to 
discardable decls.


================
Comment at: clang/lib/AST/TextNodeDumper.cpp:1622
+  if (D->isModuleUnreachable())
+    OS << " ModuleUnreachable";
 }
----------------
ChuanqiXu wrote:
> iains wrote:
> > ChuanqiXu wrote:
> > > It may be better to keep the consistent style.
> > I don't think that is a matter of style `__module_private__` is a keyword 
> > used elsewhere?
> > 
> > If you look though the file you will see mostly that the printed output 
> > does not prepend or append underscores.
> > 
> > BTW, similar changes are probably needed in other node printers, this was 
> > done early to add debug.
> Oh, I found `__module_private__ ` is a keyword in clang modules. I didn't 
> recognize it. Even in this case, I still prefer to keep the style 
> consistently. I think users would be more comfortable to read consistent 
> symbols. Also I think it is acceptable to keep `ModuleUnreachable` since it 
> doesn't matter a lot to me.
OK we now have more fine-grained output for the module ownership in the dumps 
which allows specific tests to be constructed.  At present, the naming is as 
per decl.h (with the single exception of __module_private__ which has a 
user-facing representation).


================
Comment at: clang/lib/Sema/Sema.cpp:1130
     DiagnoseUseOfUnimplementedSelectors();
 
+    // For C++20 modules, we are permitted to elide decls in the Global
----------------
ChuanqiXu wrote:
> I prefer to wrap this logic to a function to make it easier to read.
I think the comment refers to an older version of the changes.


================
Comment at: clang/lib/Sema/Sema.cpp:1131-1133
+    // For C++20 modules, we are permitted to elide decls in the Global
+    // Module Fragment of a module interface if they are unused in the body
+    // of the interface.
----------------
ChuanqiXu wrote:
> I prefer to cite the standard. And the original comment looks not so right 
> (since we don't and couldn't remove a declaration in GMF due to it is not 
> used by the body of the interface)
this is now implemented differently, 


================
Comment at: clang/lib/Sema/Sema.cpp:1138-1141
+      for (DeclContext::decl_iterator DI = DC->decls_begin(),
+                                      DEnd = DC->decls_end();
+           DI != DEnd; ++DI) {
+        Decl *D = *DI;
----------------
ChuanqiXu wrote:
> Prefer range based loop.
this is now implemented differently


================
Comment at: clang/lib/Sema/Sema.cpp:1146
+        M = D->getOwningModule();
+        if (!M || !D->getOwningModule()->isGlobalModule())
+          continue;
----------------
ChuanqiXu wrote:
> `M == GlobalModuleFragment` says that M is a global module fragment in the 
> current TU explicitly. The original implementation doesn't check if M is in 
> the current TU or not.
this is now implemented differently


================
Comment at: clang/lib/Sema/Sema.cpp:1150
+          continue;
+        if (!D->isUsed(false) && !D->isReferenced())
+          WorkList.push_back(D);
----------------
rsmith wrote:
> rsmith wrote:
> > ChuanqiXu wrote:
> > > Should we check for `D->isUsed()` simply? It looks more straight forward 
> > > to me.
> > Does this work properly if the declaration is referenced within the header 
> > unit? I think we track whether we've seen any use of the declaration 
> > anywhere, not only if we've seen a use in the current translation unit, and 
> > we'll need a different mechanism here.
> s/header unit/global module fragment/
this is now implemented differently


================
Comment at: clang/lib/Sema/SemaModule.cpp:916-920
+            markGMFDeclsReachableFrom(Target, /*MakeVisible*/ true);
+          }
+        } else {
+          markGMFDeclsReachableFrom(Child, /*MakeVisible*/ true);
+        }
----------------
rsmith wrote:
> Do we need the special `MakeVisible` handling here? I would have thought that 
> it would be sufficient for `Child` itself to be visible. Making the target of 
> a using declaration visible seems like it would do the wrong thing for a case 
> like:
> 
> ```
> module;
> int f();
> export module M;
> namespace N { export using ::f; }
> ```
> 
> ```
> import M;
> int a = f(); // should be an error, ::f should not be visible
> int b = N::f(); // should be OK, UsingShadowDecl is visible
> ```
> 
> I wonder if we need any special handling here at all -- if the GMF decls are 
> referenced by something in an `export` block, then I'd have expected they'll 
> already be marked as used and that marking would have marked them as 
> reachable.
> Do we need the special `MakeVisible` handling here? I would have thought that 
> it would be sufficient for `Child` itself to be visible. Making the target of 
> a using declaration visible seems like it would do the wrong thing for a case 
> like:
> 
> ```
> module;
> int f();
> export module M;
> namespace N { export using ::f; }
> ```
> 
> ```
> import M;
> int a = f(); // should be an error, ::f should not be visible
> int b = N::f(); // should be OK, UsingShadowDecl is visible
> ```

fixed, and added a test case to cover this.

> I wonder if we need any special handling here at all -- if the GMF decls are 
> referenced by something in an `export` block, then I'd have expected they'll 
> already be marked as used and that marking would have marked them as 
> reachable.

Indeed. this was over cautious,  However,  the one case that we have to cover 
is the target of a using decl - those are neither marked `used` nor 
`referenced`. 


================
Comment at: clang/lib/Sema/SemaModule.cpp:1024-1036
+  // Only visit each Decl once.
+  if (!SeenDecls.insert(Orig).second)
+    return;
+
+  // Do not alter the ownership unless it is ModuleDiscardable.
+  if (Orig->isModuleDiscardable()) {
+    assert(Orig->getOwningModule() &&
----------------
rsmith wrote:
> Instead of storing a `SeenDecls` set and checking it here, is it feasible to 
> check whether we're transitioning this declaration from discardable to 
> retained, and only doing the work below if so?
I had that as my original implementation, which I revised to do the same kind 
of thing as the type pointers.  However, the check for isModuleDiscardable is 
cheaper, indeed.

(JFTR, I also tried an implementation with a decl visitor, but it did not seem 
to be any less complex or really any shorter code-wise)

I cannot see how we can avoid tracking the types.


================
Comment at: clang/lib/Sema/SemaModule.cpp:978
+void Sema::markReachableGMFDecls(Decl *Orig) {
+
+  if (isa<FunctionDecl>(*Orig)) {
----------------
ChuanqiXu wrote:
> iains wrote:
> > ChuanqiXu wrote:
> > > It looks better to add assumption as an assertion .
> > what is `D` here?
> > `markReachableGMFDecls` is only called in the case that `Orig` is **not** 
> > discarded (we are marking decls as reachable because they are `used` in the 
> > interface..
> > 
> Oh, `D` should be `Orig`, my bad. Yeah, I found `markReachableGMFDecls ` is 
> only called when `Orig` is not discarded. So I suggest to add the assertion 
> to make it explicit and clear and it could avoid misuse in the future.
in the revised code, we have an assert.


================
Comment at: clang/test/CXX/basic/basic.scope/basic.scope.namespace/p2.cpp:32
 void test_early() {
-  in_header = 1; // expected-error {{missing '#include "foo.h"'; 'in_header' 
must be declared before it is used}}
-  // expected-note@*{{not visible}}
+  in_header = 1; // expected-error {{use of undeclared identifier 'in_header'}}
 
----------------
ChuanqiXu wrote:
> iains wrote:
> > ChuanqiXu wrote:
> > > iains wrote:
> > > > ChuanqiXu wrote:
> > > > > This error message looks worse. I image I could hear users 
> > > > > complaining this. (I doesn't say it is your fault since this is 
> > > > > specified in standard and the standard cases are harder to 
> > > > > understand). I want to know if this is consistent with GCC?
> > > > > This error message looks worse. I image I could hear users 
> > > > > complaining this. (I doesn't say it is your fault since this is 
> > > > > specified in standard and the standard cases are harder to 
> > > > > understand). I want to know if this is consistent with GCC?
> > > > 
> > > > As you say, the standard says "neither reachable nor visible" 
> > > > if it's not reachable then. we would not have the information that it 
> > > > was from header foo.h so we cannot form the nicer diagnostic.
> > > > 
> > > > Perhaps we need to invent "reachable for diagnostics" ... which I'd 
> > > > rather not divert effort to right now.
> > > > 
> > > Maybe we could make a new diagnostic message.
> > I do not think it is a matter of a diagnostic message.
> > 
> > If we omit the decl from the BMI (which we are permitted to do if it is 
> > ModuleUnreachable), then it cannot be found and therefore the information 
> > on which header it came from would not be available.
> > 
> Your word makes sense.
in the current implementation, we mark the decls but do not yet actually remove 
them - so that the better diagnostic should still be available.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D126694

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

Reply via email to