iains updated this revision to Diff 434417.
iains added a comment.
Herald added a reviewer: aaron.ballman.

this is a re-write - please see additional comments on the revised direction.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D126694

Files:
  clang/include/clang/AST/DeclBase.h
  clang/include/clang/Sema/Lookup.h
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/Decl.cpp
  clang/lib/AST/TextNodeDumper.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/lib/Sema/SemaInit.cpp
  clang/lib/Sema/SemaLambda.cpp
  clang/lib/Sema/SemaModule.cpp
  clang/lib/Sema/SemaOpenMP.cpp
  clang/lib/Sema/SemaStmt.cpp
  clang/lib/Sema/SemaStmtAsm.cpp
  clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
  clang/lib/Serialization/ASTReaderDecl.cpp
  clang/lib/Serialization/ASTWriterDecl.cpp
  clang/test/CXX/basic/basic.scope/basic.scope.namespace/p2.cpp

Index: clang/test/CXX/basic/basic.scope/basic.scope.namespace/p2.cpp
===================================================================
--- clang/test/CXX/basic/basic.scope/basic.scope.namespace/p2.cpp
+++ clang/test/CXX/basic/basic.scope/basic.scope.namespace/p2.cpp
@@ -29,8 +29,7 @@
 #endif
 
 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'}}
 
   global_module_fragment = 1; // expected-error {{missing '#include'; 'global_module_fragment' must be declared before it is used}}
   // expected-n...@p2.cpp:16 {{not visible}}
@@ -54,8 +53,7 @@
 #endif
 
 void test_late() {
-  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'}}
 
   global_module_fragment = 1; // expected-error {{missing '#include'; 'global_module_fragment' must be declared before it is used}}
   // expected-n...@p2.cpp:16 {{not visible}}
Index: clang/lib/Serialization/ASTWriterDecl.cpp
===================================================================
--- clang/lib/Serialization/ASTWriterDecl.cpp
+++ clang/lib/Serialization/ASTWriterDecl.cpp
@@ -312,6 +312,7 @@
   Record.push_back(D->isTopLevelDeclInObjCContainer());
   Record.push_back(D->getAccess());
   Record.push_back(D->isModulePrivate());
+  Record.push_back(D->isModuleUnreachable());
   Record.push_back(Writer.getSubmoduleID(D->getOwningModule()));
 
   // If this declaration injected a name into a context different from its
@@ -394,6 +395,7 @@
       !D->isInvalidDecl() &&
       !D->isTopLevelDeclInObjCContainer() &&
       !D->isModulePrivate() &&
+      !D->isModuleUnreachable() &&
       !needsAnonymousDeclarationNumber(D) &&
       D->getDeclName().getNameKind() == DeclarationName::Identifier)
     AbbrevToUse = Writer.getDeclTypedefAbbrev();
@@ -464,6 +466,7 @@
       !D->isTopLevelDeclInObjCContainer() &&
       D->getAccess() == AS_none &&
       !D->isModulePrivate() &&
+      !D->isModuleUnreachable() &&
       !CXXRecordDecl::classofKind(D->getKind()) &&
       !D->getIntegerTypeSourceInfo() &&
       !D->getMemberSpecializationInfo() &&
@@ -501,6 +504,7 @@
       !D->isTopLevelDeclInObjCContainer() &&
       D->getAccess() == AS_none &&
       !D->isModulePrivate() &&
+      !D->isModuleUnreachable() &&
       !CXXRecordDecl::classofKind(D->getKind()) &&
       !needsAnonymousDeclarationNumber(D) &&
       D->getDeclName().getNameKind() == DeclarationName::Identifier)
@@ -803,6 +807,7 @@
       !D->isInvalidDecl() &&
       !D->isReferenced() &&
       !D->isModulePrivate() &&
+      !D->isModuleUnreachable() &&
       !D->getBitWidth() &&
       !D->hasExtInfo() &&
       D->getDeclName())
@@ -938,6 +943,7 @@
       !D->isReferenced() &&
       !D->isTopLevelDeclInObjCContainer() &&
       !D->isModulePrivate() &&
+      !D->isModuleUnreachable() &&
       !D->getBitWidth() &&
       !D->hasInClassInitializer() &&
       !D->hasCapturedVLAType() &&
@@ -1069,6 +1075,7 @@
       !D->isTopLevelDeclInObjCContainer() &&
       D->getAccess() == AS_none &&
       !D->isModulePrivate() &&
+      !D->isModuleUnreachable() &&
       !needsAnonymousDeclarationNumber(D) &&
       D->getDeclName().getNameKind() == DeclarationName::Identifier &&
       !D->hasExtInfo() &&
@@ -1117,6 +1124,7 @@
       !D->isReferenced() &&
       D->getAccess() == AS_none &&
       !D->isModulePrivate() &&
+      !D->isModuleUnreachable() &&
       D->getStorageClass() == 0 &&
       D->getInitStyle() == VarDecl::CInit && // Can params have anything else?
       D->getFunctionScopeDepth() == 0 &&
@@ -1929,6 +1937,7 @@
   Abv->Add(BitCodeAbbrevOp(0));                   // TopLevelDeclInObjCContainer
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2));  // AccessSpecifier
   Abv->Add(BitCodeAbbrevOp(0));                       // ModulePrivate
+  Abv->Add(BitCodeAbbrevOp(0));                       // ModuleUnreachable
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
   // NamedDecl
   Abv->Add(BitCodeAbbrevOp(0));                       // NameKind = Identifier
@@ -1962,6 +1971,7 @@
   Abv->Add(BitCodeAbbrevOp(0));                   // TopLevelDeclInObjCContainer
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2));  // AccessSpecifier
   Abv->Add(BitCodeAbbrevOp(0));                       // ModulePrivate
+  Abv->Add(BitCodeAbbrevOp(0));                       // ModuleUnreachable
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
   // NamedDecl
   Abv->Add(BitCodeAbbrevOp(0));                       // NameKind = Identifier
@@ -2000,6 +2010,7 @@
   Abv->Add(BitCodeAbbrevOp(0));                   // TopLevelDeclInObjCContainer
   Abv->Add(BitCodeAbbrevOp(AS_none));                 // C++ AccessSpecifier
   Abv->Add(BitCodeAbbrevOp(0));                       // ModulePrivate
+  Abv->Add(BitCodeAbbrevOp(0));                       // ModuleUnreachable
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
   // NamedDecl
   Abv->Add(BitCodeAbbrevOp(0));                       // NameKind = Identifier
@@ -2050,6 +2061,7 @@
   Abv->Add(BitCodeAbbrevOp(0));                   // TopLevelDeclInObjCContainer
   Abv->Add(BitCodeAbbrevOp(AS_none));                 // C++ AccessSpecifier
   Abv->Add(BitCodeAbbrevOp(0));                       // ModulePrivate
+  Abv->Add(BitCodeAbbrevOp(0));                       // ModuleUnreachable
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
   // NamedDecl
   Abv->Add(BitCodeAbbrevOp(0));                       // NameKind = Identifier
@@ -2112,6 +2124,7 @@
   Abv->Add(BitCodeAbbrevOp(0));                   // TopLevelDeclInObjCContainer
   Abv->Add(BitCodeAbbrevOp(AS_none));                 // C++ AccessSpecifier
   Abv->Add(BitCodeAbbrevOp(0));                       // ModulePrivate
+  Abv->Add(BitCodeAbbrevOp(0));                       // ModuleUnreachable
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
   // NamedDecl
   Abv->Add(BitCodeAbbrevOp(0));                       // NameKind = Identifier
@@ -2160,6 +2173,7 @@
   Abv->Add(BitCodeAbbrevOp(0));                   // TopLevelDeclInObjCContainer
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // C++ AccessSpecifier
   Abv->Add(BitCodeAbbrevOp(0));                       // ModulePrivate
+  Abv->Add(BitCodeAbbrevOp(0));                       // ModuleUnreachable
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
   // NamedDecl
   Abv->Add(BitCodeAbbrevOp(0));                       // NameKind = Identifier
@@ -2189,6 +2203,7 @@
   Abv->Add(BitCodeAbbrevOp(0));                   // TopLevelDeclInObjCContainer
   Abv->Add(BitCodeAbbrevOp(AS_none));                 // C++ AccessSpecifier
   Abv->Add(BitCodeAbbrevOp(0));                       // ModulePrivate
+  Abv->Add(BitCodeAbbrevOp(0));                       // ModuleUnreachable
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
   // NamedDecl
   Abv->Add(BitCodeAbbrevOp(0));                       // NameKind = Identifier
@@ -2241,6 +2256,7 @@
   Abv->Add(BitCodeAbbrevOp(0));                         // InObjCContainer
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Access
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ModulePrivate
+  Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ModuleUnreachable
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));   // SubmoduleID
   // NamedDecl
   Abv->Add(BitCodeAbbrevOp(DeclarationName::Identifier)); // NameKind
Index: clang/lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- clang/lib/Serialization/ASTReaderDecl.cpp
+++ clang/lib/Serialization/ASTReaderDecl.cpp
@@ -606,14 +606,16 @@
   D->setAccess((AccessSpecifier)Record.readInt());
   D->FromASTFile = true;
   bool ModulePrivate = Record.readInt();
+  bool ModuleUnreachable = Record.readInt();
 
   // Determine whether this declaration is part of a (sub)module. If so, it
   // may not yet be visible.
   if (unsigned SubmoduleID = readSubmoduleID()) {
     // Store the owning submodule ID in the declaration.
     D->setModuleOwnershipKind(
-        ModulePrivate ? Decl::ModuleOwnershipKind::ModulePrivate
-                      : Decl::ModuleOwnershipKind::VisibleWhenImported);
+        ModuleUnreachable ? Decl::ModuleOwnershipKind::ModuleUnreachable
+                          : ModulePrivate ? Decl::ModuleOwnershipKind::ModulePrivate
+                                          : Decl::ModuleOwnershipKind::VisibleWhenImported);
     D->setOwningModuleID(SubmoduleID);
 
     if (ModulePrivate) {
@@ -629,6 +631,8 @@
       else
         Reader.HiddenNamesMap[Owner].push_back(D);
     }
+  } else if (ModuleUnreachable) {
+    D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModuleUnreachable);
   } else if (ModulePrivate) {
     D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModulePrivate);
   }
Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1004,7 +1004,7 @@
     SemaRef.inferGslPointerAttribute(Typedef);
 
   Typedef->setAccess(D->getAccess());
-  Typedef->setReferenced(D->isReferenced());
+  SemaRef.setDeclReferenced(Typedef, D->isReferenced());
 
   return Typedef;
 }
@@ -1069,7 +1069,7 @@
 Decl *TemplateDeclInstantiator::VisitBindingDecl(BindingDecl *D) {
   auto *NewBD = BindingDecl::Create(SemaRef.Context, Owner, D->getLocation(),
                                     D->getIdentifier());
-  NewBD->setReferenced(D->isReferenced());
+  SemaRef.setDeclReferenced(NewBD, D->isReferenced());
   SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, NewBD);
   return NewBD;
 }
@@ -5210,8 +5210,8 @@
 
   if (!OldVar->isStaticDataMember()) {
     if (OldVar->isUsed(false))
-      NewVar->setIsUsed();
-    NewVar->setReferenced(OldVar->isReferenced());
+      setDeclIsUsed(NewVar);
+    setDeclReferenced(static_cast<Decl*>(NewVar), OldVar->isReferenced());
   }
 
   InstantiateAttrs(TemplateArgs, OldVar, NewVar, LateAttrs, StartingScope);
Index: clang/lib/Sema/SemaStmtAsm.cpp
===================================================================
--- clang/lib/Sema/SemaStmtAsm.cpp
+++ clang/lib/Sema/SemaStmtAsm.cpp
@@ -956,7 +956,7 @@
 
   if (Label->isMSAsmLabel()) {
     // If we have previously created this label implicitly, mark it as used.
-    Label->markUsed(Context);
+    markDeclUsed(Label, Context);
   } else {
     // Otherwise, insert it, but only resolve it if we have seen the label itself.
     std::string InternalName;
Index: clang/lib/Sema/SemaStmt.cpp
===================================================================
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -2751,7 +2751,7 @@
 
   if (RangeVarType->isDependentType()) {
     // The range is implicitly used as a placeholder when it is dependent.
-    RangeVar->markUsed(Context);
+    markDeclUsed(static_cast<Decl*>(RangeVar), Context);
 
     // Deduce any 'auto's in the loop variable as 'DependentTy'. We'll fill
     // them in properly when we instantiate the loop.
@@ -3266,7 +3266,7 @@
                                SourceLocation LabelLoc,
                                LabelDecl *TheDecl) {
   setFunctionHasBranchIntoScope();
-  TheDecl->markUsed(Context);
+  markDeclUsed(TheDecl, Context);
   return new (Context) GotoStmt(TheDecl, GotoLoc, LabelLoc);
 }
 
Index: clang/lib/Sema/SemaOpenMP.cpp
===================================================================
--- clang/lib/Sema/SemaOpenMP.cpp
+++ clang/lib/Sema/SemaOpenMP.cpp
@@ -1455,7 +1455,7 @@
                                      SourceLocation Loc,
                                      bool RefersToCapture = false) {
   D->setReferenced();
-  D->markUsed(S.Context);
+  S.markDeclUsed(D, S.Context);
   return DeclRefExpr::Create(S.getASTContext(), NestedNameSpecifierLoc(),
                              SourceLocation(), D, RefersToCapture, Loc, Ty,
                              VK_LValue);
@@ -3004,7 +3004,7 @@
 
     // Mark variable as used.
     VD->setReferenced();
-    VD->markUsed(Context);
+    markDeclUsed(static_cast<Decl *>(VD), Context);
 
     QualType QType = VD->getType();
     if (QType->isDependentType() || QType->isInstantiationDependentType()) {
Index: clang/lib/Sema/SemaModule.cpp
===================================================================
--- clang/lib/Sema/SemaModule.cpp
+++ clang/lib/Sema/SemaModule.cpp
@@ -83,14 +83,18 @@
     return nullptr;
   }
 
-  // We start in the global module; all those declarations are implicitly
-  // module-private (though they do not have module linkage).
   Module *GlobalModule =
       PushGlobalModuleFragment(ModuleLoc, /*IsImplicit=*/false);
 
   // All declarations created from now on are owned by the global module.
   auto *TU = Context.getTranslationUnitDecl();
-  TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::Visible);
+  // For C++20 modules, we are expected to elide GMF decls that are not used
+  // in the purview of the named module.  In order to do that, create GMF decls
+  // with a marker that is updated when a decl is used.
+  if (getLangOpts().CPlusPlusModules)
+    TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModuleUnreachable);
+  else
+    TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::Visible);
   TU->setLocalOwningModule(GlobalModule);
 
   // FIXME: Consider creating an explicit representation of this declaration.
@@ -254,9 +258,8 @@
   const_cast<LangOptions&>(getLangOpts()).CurrentModule = ModuleName;
 
   auto &Map = PP.getHeaderSearchInfo().getModuleMap();
-  Module *Mod;
-
-  ImportDecl *Import = nullptr;
+  Module *Mod; // The module we are creating.
+  Module *Interface = nullptr; // The interface fir an implementation.
   switch (MDK) {
   case ModuleDeclKind::Interface:
   case ModuleDeclKind::PartitionInterface: {
@@ -291,22 +294,18 @@
     // declaration.
 
     // First find the interface we need to import.
-    Mod = getModuleLoader().loadModule(ModuleLoc, {ModuleNameLoc},
-                                       Module::AllVisible,
-                                       /*IsInclusionDirective=*/false);
-    if (!Mod) {
+    Interface = getModuleLoader().loadModule(ModuleLoc, {ModuleNameLoc},
+                                             Module::AllVisible,
+                                             /*IsInclusionDirective=*/false);
+    if (!Interface) {
       Diag(ModuleLoc, diag::err_module_not_defined) << ModuleName;
       // Create an empty module interface unit for error recovery.
       Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName,
                                              GlobalModuleFragment);
-    } else {
-      // Make the decl.
-      Import = ImportDecl::Create(Context, CurContext, ModuleLoc, Mod,
-                                  Path[0].second);
-      // now create the implementation module
+    } else
+      // We found the interface, now create the implementation module
       Mod = Map.createModuleForImplementationUnit(ModuleLoc, ModuleName,
                                                   GlobalModuleFragment);
-    }
   } break;
 
   case ModuleDeclKind::PartitionImplementation:
@@ -348,13 +347,23 @@
   // We already potentially made an implicit import (in the case of a module
   // implementation unit importing its interface).  Make this module visible
   // and return the import decl to be added to the current TU.
-  if (Import)
-    VisibleModules.setVisible(Import->getImportedModule(), ModuleLoc);
-
+  if (Interface) {
+    // Make the import decl for the interface.
+    ImportDecl *Import = ImportDecl::Create(Context, CurContext, ModuleLoc,
+                                            Interface, Path[0].second);
+    VisibleModules.setVisible(Interface, ModuleLoc);
+    if (auto *InterfaceGMF = Interface->getGlobalModuleFragment())
+      // The fact that the GMF is a seaprate sub-module is an implementation
+      // detail, if it's present then it should also be made visible here.
+      // Elision of unreachable decls is handled by marking them.
+      VisibleModules.setVisible(InterfaceGMF, ModuleLoc);
+
+    // If we made an implicit import of the module interface, then return the
+    // imported module decl.
+    return ConvertDeclToDeclGroup(Import);
+  }
   // FIXME: Create a ModuleDecl.
-  // If we made an implicit import of the module interface, then return the
-  // imported module decl.
-  return Import ? ConvertDeclToDeclGroup(Import) : nullptr;
+  return nullptr;
 }
 
 Sema::DeclGroupPtrTy
@@ -942,3 +951,56 @@
          "left the wrong module scope, which is not global module fragment");
   ModuleScopes.pop_back();
 }
+
+// A helper to recurse through the statement tree finding DeclRefExprs and
+// marking the referenced decls as reachable.
+static void FindDeclRefExprs(clang::Stmt *S) {
+  if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S)) {
+    auto *D = DR->getFoundDecl();
+//    llvm::dbgs() << "DR:"; D->dump();
+    if (D->isModuleUnreachable()) {
+       D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::Visible);
+    }
+  } else
+    for (auto *CH : S->children())
+      FindDeclRefExprs(CH);
+}
+
+// Given that we mark a decl 'orig' as reachable, this then analyzes that decl
+// to determine if it, in turn, makes other decls reachable.  We can simplify
+// some checking here - we know we are in a module purview.
+void Sema::markReachableGMFDecls(Decl *Orig) {
+
+  if (isa<FunctionDecl>(*Orig)) {
+    auto *FD = cast<FunctionDecl>(Orig);
+    for (auto *P : FD->parameters()) {
+//      bool Changed = false;
+      if (P->isModuleUnreachable()) {
+        P->setModuleOwnershipKind(Decl::ModuleOwnershipKind::Visible);
+//        Changed = true;
+      }
+      if (auto *E = P->getDefaultArg()) {
+        if (isa<CallExpr>(*E)) {
+          Decl *D = cast<CallExpr>(E)->getCalleeDecl();
+          if (D->isModuleUnreachable()) {
+            D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::Visible);
+//            Changed = true;
+          }
+        }
+      }
+//      if (Changed) {
+//       llvm::dbgs() << "P:"; P->dump();
+//      }
+    }
+    const FunctionDecl *BodyDecl;
+    if (auto *S = FD->getBody(BodyDecl)) {
+      FindDeclRefExprs(S);
+    }
+  } else if (isa<VarDecl>(*Orig)) {
+    auto *VD = cast<VarDecl>(Orig);
+    QualType T = VD->getTypeSourceInfo()
+      ? VD->getTypeSourceInfo()->getType()
+      : VD->getASTContext().getUnqualifiedObjCPointerType(VD->getType());
+    T.dump();
+  }
+}
Index: clang/lib/Sema/SemaLambda.cpp
===================================================================
--- clang/lib/Sema/SemaLambda.cpp
+++ clang/lib/Sema/SemaLambda.cpp
@@ -874,7 +874,7 @@
   NewVD->setReferenced(true);
   // FIXME: Pass in a VarDecl::InitializationStyle.
   NewVD->setInitStyle(static_cast<VarDecl::InitializationStyle>(InitStyle));
-  NewVD->markUsed(Context);
+  markDeclUsed(static_cast<Decl*>(NewVD), Context);
   NewVD->setInit(Init);
   if (NewVD->isParameterPack())
     getCurLambda()->LocalPacks.push_back(NewVD);
@@ -1975,7 +1975,7 @@
         Lambda->lookup(
           Context.DeclarationNames.getCXXOperatorName(OO_Call)).front());
   CallOperator->setReferenced();
-  CallOperator->markUsed(Context);
+  markDeclUsed(CallOperator, Context);
 
   ExprResult Init = PerformCopyInitialization(
       InitializedEntity::InitializeLambdaToBlock(ConvLocation, Src->getType()),
Index: clang/lib/Sema/SemaInit.cpp
===================================================================
--- clang/lib/Sema/SemaInit.cpp
+++ clang/lib/Sema/SemaInit.cpp
@@ -4692,7 +4692,7 @@
   FunctionDecl *Function = Best->Function;
   // This is the overload that will be used for this initialization step if we
   // use this initialization. Mark it as referenced.
-  Function->setReferenced();
+  S.setDeclReferenced(Function);
 
   // Compute the returned type and value kind of the conversion.
   QualType cv3T3;
@@ -5363,7 +5363,7 @@
   }
 
   FunctionDecl *Function = Best->Function;
-  Function->setReferenced();
+  S.setDeclReferenced(Function);
   bool HadMultipleCandidates = (CandidateSet.size() > 1);
 
   if (isa<CXXConstructorDecl>(Function)) {
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -47,6 +47,7 @@
 #include "clang/Sema/ParsedTemplate.h"
 #include "clang/Sema/Scope.h"
 #include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/Sema.h"
 #include "clang/Sema/SemaFixItUtils.h"
 #include "clang/Sema/SemaInternal.h"
 #include "clang/Sema/Template.h"
@@ -15719,7 +15720,7 @@
 /// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo".
 ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc,
                                 LabelDecl *TheDecl) {
-  TheDecl->markUsed(Context);
+  markDeclUsed(TheDecl, Context);
   // Create the AST node.  The address of a label always has type 'void*'.
   return new (Context) AddrLabelExpr(OpLoc, LabLoc, TheDecl,
                                      Context.getPointerType(Context.VoidTy));
@@ -17804,7 +17805,7 @@
                                   bool MightBeOdrUse) {
   assert(Func && "No function?");
 
-  Func->setReferenced();
+  setDeclReferenced(Func);
 
   // Recursive functions aren't really used until they're used from some other
   // context.
@@ -18037,7 +18038,7 @@
       }
     }
 
-    Func->markUsed(Context);
+    markDeclUsed(Func, Context);
   }
 }
 
@@ -18108,7 +18109,7 @@
     }
   }
 
-  Var->markUsed(SemaRef.Context);
+  SemaRef.markDeclUsed(Var, SemaRef.Context);
 }
 
 void Sema::MarkCaptureUsedInEnclosingContext(VarDecl *Capture,
@@ -19264,7 +19265,7 @@
   assert((!E || isa<DeclRefExpr>(E) || isa<MemberExpr>(E) ||
           isa<FunctionParmPackExpr>(E)) &&
          "Invalid Expr argument to DoMarkVarDeclReferenced");
-  Var->setReferenced();
+  SemaRef.setDeclReferenced(Var);
 
   if (Var->isInvalidDecl())
     return;
@@ -19540,7 +19541,7 @@
     MarkFunctionReferenced(Loc, FD, MightBeOdrUse);
     return;
   }
-  D->setReferenced();
+  setDeclReferenced(D);
 }
 
 namespace {
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -8797,7 +8797,7 @@
       return;
     }
     FD->setBody(Body.get());
-    FD->markUsed(Context);
+    markDeclUsed(FD,Context);
   }
 
   // The exception specification is needed because we are defining the
@@ -13491,7 +13491,7 @@
                            ? Constructor->getEndLoc()
                            : Constructor->getLocation();
   Constructor->setBody(new (Context) CompoundStmt(Loc));
-  Constructor->markUsed(Context);
+  markDeclUsed(Constructor,Context);
 
   if (ASTMutationListener *L = getASTMutationListener()) {
     L->CompletedImplicitDefinition(Constructor);
@@ -13670,7 +13670,7 @@
   }
 
   Constructor->setBody(new (Context) CompoundStmt(InitLoc));
-  Constructor->markUsed(Context);
+  markDeclUsed(Constructor, Context);
 
   if (ASTMutationListener *L = getASTMutationListener()) {
     L->CompletedImplicitDefinition(Constructor);
@@ -13781,7 +13781,7 @@
                            ? Destructor->getEndLoc()
                            : Destructor->getLocation();
   Destructor->setBody(new (Context) CompoundStmt(Loc));
-  Destructor->markUsed(Context);
+  markDeclUsed(Destructor, Context);
 
   if (ASTMutationListener *L = getASTMutationListener()) {
     L->CompletedImplicitDefinition(Destructor);
@@ -14640,7 +14640,7 @@
     assert(!Body.isInvalid() && "Compound statement creation cannot fail");
   }
   CopyAssignOperator->setBody(Body.getAs<Stmt>());
-  CopyAssignOperator->markUsed(Context);
+  markDeclUsed(CopyAssignOperator, Context);
 
   if (ASTMutationListener *L = getASTMutationListener()) {
     L->CompletedImplicitDefinition(CopyAssignOperator);
@@ -15010,7 +15010,7 @@
     assert(!Body.isInvalid() && "Compound statement creation cannot fail");
   }
   MoveAssignOperator->setBody(Body.getAs<Stmt>());
-  MoveAssignOperator->markUsed(Context);
+  markDeclUsed(MoveAssignOperator, Context);
 
   if (ASTMutationListener *L = getASTMutationListener()) {
     L->CompletedImplicitDefinition(MoveAssignOperator);
@@ -15154,7 +15154,7 @@
     Sema::CompoundScopeRAII CompoundScope(*this);
     CopyConstructor->setBody(
         ActOnCompoundStmt(Loc, Loc, None, /*isStmtExpr=*/false).getAs<Stmt>());
-    CopyConstructor->markUsed(Context);
+    markDeclUsed(CopyConstructor, Context);
   }
 
   if (ASTMutationListener *L = getASTMutationListener()) {
@@ -15280,7 +15280,7 @@
     Sema::CompoundScopeRAII CompoundScope(*this);
     MoveConstructor->setBody(ActOnCompoundStmt(
         Loc, Loc, None, /*isStmtExpr=*/ false).getAs<Stmt>());
-    MoveConstructor->markUsed(Context);
+    markDeclUsed(MoveConstructor, Context);
   }
 
   if (ASTMutationListener *L = getASTMutationListener()) {
@@ -15331,7 +15331,7 @@
   // Fill in the __invoke function with a dummy implementation. IR generation
   // will fill in the actual details. Update its type in case it contained
   // an 'auto'.
-  Invoker->markUsed(Context);
+  markDeclUsed(Invoker, Context);
   Invoker->setReferenced();
   Invoker->setType(Conv->getReturnType()->getPointeeType());
   Invoker->setBody(new (Context) CompoundStmt(Conv->getLocation()));
@@ -15343,7 +15343,7 @@
   Stmt *Return = BuildReturnStmt(Conv->getLocation(), FunctionRef).get();
   Conv->setBody(CompoundStmt::Create(Context, Return, Conv->getLocation(),
                                      Conv->getLocation()));
-  Conv->markUsed(Context);
+  markDeclUsed(Conv, Context);
   Conv->setReferenced();
 
   if (ASTMutationListener *L = getASTMutationListener()) {
@@ -15398,7 +15398,7 @@
   Stmt *ReturnS = Return.get();
   Conv->setBody(CompoundStmt::Create(Context, ReturnS, Conv->getLocation(),
                                      Conv->getLocation()));
-  Conv->markUsed(Context);
+  markDeclUsed(Conv, Context);
 
   // We're done; notify the mutation listener, if any.
   if (ASTMutationListener *L = getASTMutationListener()) {
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -2012,7 +2012,7 @@
     LookupResult LR(S, target, Sema::LookupOrdinaryName);
     if (S.LookupQualifiedName(LR, S.getCurLexicalContext()))
       for (NamedDecl *ND : LR)
-        ND->markUsed(S.Context);
+        S.markDeclUsed(ND, S.Context);
   }
 
   D->addAttr(::new (S.Context) AliasAttr(S.Context, AL, Str));
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -4121,7 +4121,7 @@
 
   // Merge "used" flag.
   if (Old->getMostRecentDecl()->isUsed(false))
-    New->setIsUsed();
+    setDeclIsUsed(New);
 
   // Merge attributes from the parameters.  These can mismatch with K&R
   // declarations.
@@ -4537,7 +4537,7 @@
 
   // Merge "used" flag.
   if (Old->getMostRecentDecl()->isUsed(false))
-    New->setIsUsed();
+    setDeclIsUsed(New);
 
   // Keep a chain of previous declarations.
   New->setPreviousDecl(Old);
Index: clang/lib/AST/TextNodeDumper.cpp
===================================================================
--- clang/lib/AST/TextNodeDumper.cpp
+++ clang/lib/AST/TextNodeDumper.cpp
@@ -12,6 +12,7 @@
 
 #include "clang/AST/TextNodeDumper.h"
 #include "clang/AST/APValue.h"
+#include "clang/AST/DeclBase.h"
 #include "clang/AST/DeclFriend.h"
 #include "clang/AST/DeclOpenMP.h"
 #include "clang/AST/DeclTemplate.h"
@@ -1617,6 +1618,8 @@
   dumpType(D->getUnderlyingType());
   if (D->isModulePrivate())
     OS << " __module_private__";
+  if (D->isModuleUnreachable())
+    OS << " ModuleUnreachable";
 }
 
 void TextNodeDumper::VisitEnumDecl(const EnumDecl *D) {
@@ -1629,6 +1632,8 @@
   dumpName(D);
   if (D->isModulePrivate())
     OS << " __module_private__";
+  if (D->isModuleUnreachable())
+    OS << " ModuleUnreachable";
   if (D->isFixed())
     dumpType(D->getIntegerType());
 }
@@ -1638,6 +1643,8 @@
   dumpName(D);
   if (D->isModulePrivate())
     OS << " __module_private__";
+  if (D->isModuleUnreachable())
+    OS << " ModuleUnreachable";
   if (D->isCompleteDefinition())
     OS << " definition";
 }
@@ -1668,6 +1675,8 @@
     OS << " virtual";
   if (D->isModulePrivate())
     OS << " __module_private__";
+  if (D->isModuleUnreachable())
+    OS << " ModuleUnreachable";
 
   if (D->isPure())
     OS << " pure";
@@ -1743,6 +1752,8 @@
     OS << " mutable";
   if (D->isModulePrivate())
     OS << " __module_private__";
+  if (D->isModuleUnreachable())
+    OS << " ModuleUnreachable";
 }
 
 void TextNodeDumper::VisitVarDecl(const VarDecl *D) {
@@ -1763,6 +1774,8 @@
   }
   if (D->isModulePrivate())
     OS << " __module_private__";
+  if (D->isModuleUnreachable())
+    OS << " ModuleUnreachable";
   if (D->isNRVOVariable())
     OS << " nrvo";
   if (D->isInline())
Index: clang/lib/AST/Decl.cpp
===================================================================
--- clang/lib/AST/Decl.cpp
+++ clang/lib/AST/Decl.cpp
@@ -589,6 +589,7 @@
   switch (D->getModuleOwnershipKind()) {
   case Decl::ModuleOwnershipKind::Unowned:
   case Decl::ModuleOwnershipKind::ModulePrivate:
+  case Decl::ModuleOwnershipKind::ModuleUnreachable:
     return false;
   case Decl::ModuleOwnershipKind::Visible:
   case Decl::ModuleOwnershipKind::VisibleWhenImported:
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -2263,7 +2263,37 @@
 
   bool isUsableModule(const Module *M);
 
+  /// Given a Decl D (which is from the GMF) which has been made reachable by
+  /// use, mark any additional decls which this makes reachable.
+  void markReachableGMFDecls(Decl *D);
+
+  void HandleGMFReachability(Decl *D) {
+    if (D->isModuleUnreachable() && isCurrentModulePurview()) {
+      D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::Visible);
+      markReachableGMFDecls(D);
+    }
+  }
+
 public:
+  /// To implement C++20 GMF elision semantics, we initially mark decls in the
+  /// Global Module Fragment as "ModuleUnreachable".  If the decl is then used
+  /// within the module purview, we reset that to visible.
+  void setDeclIsUsed(Decl *D) {
+    D->setIsUsed();
+    HandleGMFReachability(D);
+  }
+
+  /// Likewise when the decl is marked used and notifies mutation listeners.
+  void markDeclUsed(Decl *D, ASTContext &C) {
+    D->markUsed(C);
+    HandleGMFReachability(D);
+  }
+
+  void setDeclReferenced(Decl *D, bool R = true) {
+    D->setReferenced(R);
+    HandleGMFReachability(D);
+  }
+
   /// Get the module whose scope we are currently within.
   Module *getCurrentModule() const {
     return ModuleScopes.empty() ? nullptr : ModuleScopes.back().Module;
Index: clang/include/clang/Sema/Lookup.h
===================================================================
--- clang/include/clang/Sema/Lookup.h
+++ clang/include/clang/Sema/Lookup.h
@@ -347,6 +347,13 @@
   /// Determine whether the given declaration is visible to the
   /// program.
   static bool isVisible(Sema &SemaRef, NamedDecl *D) {
+    // [module.global.frag/note 2] A discarded declaration is neither reachable
+    // nor visible to name lookup outside the module unit, nor in template
+    // instantiations whose points of instantiation are outside the module unit,
+    // even when the instantiation context includes the module unit.
+    if (D->isFromASTFile() && D->isModuleUnreachable())
+      return false;
+
     // If this declaration is not hidden, it's visible.
     if (D->isUnconditionallyVisible())
       return true;
@@ -362,6 +369,10 @@
     if (!D->isInIdentifierNamespace(IDNS))
       return nullptr;
 
+    // see comment about [module.global.frag/note 2] above.
+    if (D->isFromASTFile() && D->isModuleUnreachable())
+      return nullptr;
+
     if (isVisible(getSema(), D) || isHiddenDeclarationVisible(D))
       return D;
 
Index: clang/include/clang/AST/DeclBase.h
===================================================================
--- clang/include/clang/AST/DeclBase.h
+++ clang/include/clang/AST/DeclBase.h
@@ -227,7 +227,12 @@
 
     /// This declaration has an owning module, but is only visible to
     /// lookups that occur within that module.
-    ModulePrivate
+    ModulePrivate,
+
+    /// This declaration is part of a Global Module Fragment, but is not
+    /// reachable or visible to importers of the named module of which the
+    /// GMF is part.
+    ModuleUnreachable
   };
 
 protected:
@@ -235,8 +240,8 @@
   /// DeclContext. These pointers form the linked list that is
   /// traversed via DeclContext's decls_begin()/decls_end().
   ///
-  /// The extra two bits are used for the ModuleOwnershipKind.
-  llvm::PointerIntPair<Decl *, 2, ModuleOwnershipKind> NextInContextAndBits;
+  /// The extra three bits are used for the ModuleOwnershipKind.
+  llvm::PointerIntPair<Decl *, 3, ModuleOwnershipKind> NextInContextAndBits;
 
 private:
   friend class DeclContext;
@@ -587,6 +592,12 @@
 
   void setReferenced(bool R = true) { Referenced = R; }
 
+  /// Whether this declaration should be retained if it is used.
+  bool isModuleUnreachable() const {
+    return getModuleOwnershipKind()
+           == Decl::ModuleOwnershipKind::ModuleUnreachable;
+  }
+
   /// Whether this declaration is a top-level declaration (function,
   /// global variable, etc.) that is lexically inside an objc container
   /// definition.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to