iains updated this revision to Diff 462657.
iains added a comment.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.
rebased and reworked.
The version here has now been tested to consume all of the libc++ headers
including
those in experimental and ext.
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/Sema.h
clang/lib/AST/Decl.cpp
clang/lib/AST/TextNodeDumper.cpp
clang/lib/Sema/Sema.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/test/AST/ast-dump-decl.c
clang/test/CXX/basic/basic.scope/basic.scope.namespace/p2.cpp
clang/test/CXX/class/class.friend/p7-cxx20.cpp
clang/test/CXX/class/class.mfct/p1-cxx20.cpp
clang/test/CXX/module/module.global.frag/cxx20-10-4-ex2.cpp
clang/test/CXX/module/module.global.frag/p3-p4.cpp
clang/test/Modules/cxx-templates.cpp
lldb/test/API/lang/cpp/gmodules/template-with-same-arg/TestTemplateWithSameArg.py
Index: lldb/test/API/lang/cpp/gmodules/template-with-same-arg/TestTemplateWithSameArg.py
===================================================================
--- lldb/test/API/lang/cpp/gmodules/template-with-same-arg/TestTemplateWithSameArg.py
+++ lldb/test/API/lang/cpp/gmodules/template-with-same-arg/TestTemplateWithSameArg.py
@@ -57,8 +57,8 @@
# Make sure we only have a single 'Member' decl on the AST
self.filecheck("target module dump ast", __file__)
-# CHECK: ClassTemplateSpecializationDecl {{.*}} imported in Module2 struct ClassInMod3 definition
-# CHECK-NEXT: |-DefinitionData pass_in_registers aggregate standard_layout trivially_copyable pod trivial
+# CHECK: ClassTemplateSpecializationDecl {{.*}} imported in Module2 struct ClassInMod3 Visible definition
+# CHECK-NEXT: |-DefinitionData Visible pass_in_registers aggregate standard_layout trivially_copyable pod trivial
# CHECK-NEXT: | |-DefaultConstructor exists trivial needs_implicit
# CHECK-NEXT: | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param
# CHECK-NEXT: | |-MoveConstructor exists simple trivial needs_implicit
Index: clang/test/Modules/cxx-templates.cpp
===================================================================
--- clang/test/Modules/cxx-templates.cpp
+++ clang/test/Modules/cxx-templates.cpp
@@ -252,7 +252,7 @@
// CHECK-DUMP: ClassTemplateDecl {{.*}} <{{.*[/\\]}}cxx-templates-common.h:1:1, {{.*}}> col:{{.*}} in cxx_templates_common SomeTemplate
// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} prev {{.*}} SomeTemplate
// CHECK-DUMP-NEXT: TemplateArgument type 'char[2]'
-// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} SomeTemplate definition
+// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} SomeTemplate Visible definition
// CHECK-DUMP-NEXT: DefinitionData
// CHECK-DUMP-NEXT: DefaultConstructor
// CHECK-DUMP-NEXT: CopyConstructor
@@ -263,7 +263,7 @@
// CHECK-DUMP-NEXT: TemplateArgument type 'char[2]'
// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} prev {{.*}} SomeTemplate
// CHECK-DUMP-NEXT: TemplateArgument type 'char[1]'
-// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} SomeTemplate definition
+// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} SomeTemplate Visible definition
// CHECK-DUMP-NEXT: DefinitionData
// CHECK-DUMP-NEXT: DefaultConstructor
// CHECK-DUMP-NEXT: CopyConstructor
Index: clang/test/CXX/module/module.global.frag/p3-p4.cpp
===================================================================
--- /dev/null
+++ clang/test/CXX/module/module.global.frag/p3-p4.cpp
@@ -0,0 +1,54 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: cd %t
+
+// RUN: %clang_cc1 -std=c++20 M.cpp -emit-module-interface -o M.pcm
+// RUN: %clang_cc1 -std=c++20 M.cpp -ast-dump | FileCheck --match-full-lines %s
+// RUN: %clang_cc1 -std=c++20 M-impl.cpp -fmodule-file=M.pcm -fsyntax-only -verify
+
+//--- p3-p4.h
+int f();
+int g();
+int h();
+int j();
+typedef int GMFInt;
+
+//--- M.cpp
+module;
+#include "p3-p4.h"
+
+export module M;
+
+export int use_f() { return f(); }
+
+export using ::h;
+
+namespace N {
+export using ::j;
+}
+
+GMFInt k(int);
+
+// CHECK: |-FunctionDecl {{.*}} <./p3-p4.h:1:1, col:7> col:5 in M.<global> hidden used f 'int ()' ReachableWhenImported
+// CHECK: |-FunctionDecl {{.*}} <line:2:1, col:7> col:5 in M.<global> hidden g 'int ()' ModuleDiscardable
+// CHECK: |-FunctionDecl {{.*}} <line:3:1, col:7> col:5 in M.<global> hidden h 'int ()' ReachableWhenImported
+// CHECK: |-FunctionDecl {{.*}} <line:4:1, col:7> col:5 in M.<global> hidden j 'int ()' ReachableWhenImported
+// CHECK: |-TypedefDecl {{.*}} <line:5:1, col:13> col:13 in M.<global> hidden referenced GMFInt 'int' ReachableWhenImported
+
+// CHECK: |-ExportDecl {{.*}} <M.cpp:6:1, col:34> col:1 in M
+// CHECK-NEXT: | `-FunctionDecl {{.*}} <col:8, col:34> col:12 in M hidden use_f 'int ()' VisibleWhenImported
+
+// CHECK: |-ExportDecl {{.*}} <line:8:1, col:16> col:1 in M
+// CHECK-NEXT: | |-UsingDecl {{.*}} <col:8, col:16> col:16 in M hidden ::h VisibleWhenImported
+// CHECK-NEXT: | `-UsingShadowDecl {{.*}} <col:16> col:16 in M hidden implicit Function {{.*}} 'h' 'int ()' VisibleWhenImported
+
+// CHECK: |-NamespaceDecl {{.*}} <line:10:1, line:12:1> line:10:11 in M hidden N
+// CHECK-NEXT: | `-ExportDecl {{.*}} <line:11:1, col:16> col:1 in M
+// CHECK-NEXT: | |-UsingDecl {{.*}} <col:8, col:16> col:16 in M hidden ::j VisibleWhenImported
+// CHECK-NEXT: | `-UsingShadowDecl {{.*}} <col:16> col:16 in M hidden implicit Function {{.*}} 'j' 'int ()' VisibleWhenImported
+
+//--- M-impl.cpp
+import M;
+int a = j(); // expected-error {{missing '#include'; 'j' must be declared before it is used}}
+ // [email protected]:4 {{declaration here is not visible}}
+int b = N::j(); // should be OK, UsingShadowDecl is visible
Index: clang/test/CXX/module/module.global.frag/cxx20-10-4-ex2.cpp
===================================================================
--- /dev/null
+++ clang/test/CXX/module/module.global.frag/cxx20-10-4-ex2.cpp
@@ -0,0 +1,60 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: cd %t
+
+// RUN: %clang_cc1 -std=c++20 std-10-4-ex2-interface.cpp \
+// RUN: -emit-module-interface -o M.pcm -Wno-unused-value
+// RUN: %clang_cc1 -std=c++20 std-10-4-ex2-implementation.cpp \
+// RUN: -fmodule-file=M.pcm -fsyntax-only -verify
+//--- std-10-4-ex2.h
+
+namespace N {
+struct X {};
+int d();
+int e();
+inline int f(X, int = d()) { return e(); }
+int g(X);
+int h(X);
+} // namespace N
+
+//--- std-10-4-ex2-interface.cpp
+
+module;
+
+#include "std-10-4-ex2.h"
+
+export module M;
+
+template <typename T> int use_f() {
+ N::X x; // N::X, N, and :: are decl-reachable from use_f
+ return f(x, 123); // N::f is decl-reachable from use_f,
+ // N::e is indirectly decl-reachable from use_f
+ // because it is decl-reachable from N::f, and
+ // N::d is decl-reachable from use_f
+ // because it is decl-reachable from N::f
+ // even though it is not used in this call
+}
+
+template <typename T> int use_g() {
+ N::X x; // N::X, N, and :: are decl-reachable from use_g
+ return g((T(), x)); // N::g is not decl-reachable from use_g
+}
+
+template <typename T> int use_h() {
+ N::X x; // N::X, N, and :: are decl-reachable from use_h
+ return h((T(), x)); // N::h is not decl-reachable from use_h, but
+ // N::h is decl-reachable from use_h<int>
+}
+
+int k = use_h<int>();
+// use_h<int> is decl-reachable from k, so
+// N::h is decl-reachable from k
+
+//--- std-10-4-ex2-implementation.cpp
+
+module M;
+
+int a = use_f<int>();
+int b = use_g<int>(); // [email protected]:20 {{use of undeclared identifier 'g'}}
+ // expected-note@-1 {{in instantiation of function template specialization 'use_g<int>' requested here}}
+int c = use_h<int>();
Index: clang/test/CXX/class/class.mfct/p1-cxx20.cpp
===================================================================
--- clang/test/CXX/class/class.mfct/p1-cxx20.cpp
+++ clang/test/CXX/class/class.mfct/p1-cxx20.cpp
@@ -48,9 +48,9 @@
void z(){};
};
-// CHECK-MOD: |-CXXRecordDecl {{.*}} <./header.h:2:1, line:4:1> line:2:7 in M.<global> hidden class A definition
-// CHECK-MOD: | |-CXXRecordDecl {{.*}} <col:1, col:7> col:7 in M.<global> hidden implicit class A
-// CHECK-MOD-NEXT: | `-CXXMethodDecl {{.*}} <line:3:3, col:12> col:8 in M.<global> hidden a 'void ()' implicit-inline
+// CHECK-MOD: |-CXXRecordDecl {{.*}} <./header.h:2:1, line:4:1> line:2:7 in M.<global> hidden class A{{( ModuleDiscardable)?}} definition
+// CHECK-MOD: | |-CXXRecordDecl {{.*}} <col:1, col:7> col:7 in M.<global> hidden implicit class A{{( ModuleDiscardable)?}}
+// CHECK-MOD-NEXT: | `-CXXMethodDecl {{.*}} <line:3:3, col:12> col:8 in M.<global> hidden a 'void ()'{{( ModuleDiscardable)?}} implicit-inline
// CHECK-MOD: `-CXXRecordDecl {{.*}} <module.cpp:6:1, line:8:1> line:6:7 in M hidden class Z{{( ReachableWhenImported)?}} definition
// CHECK-MOD: |-CXXRecordDecl {{.*}} <col:1, col:7> col:7 in M hidden implicit class Z{{( ReachableWhenImported)?}}
Index: clang/test/CXX/class/class.friend/p7-cxx20.cpp
===================================================================
--- clang/test/CXX/class/class.friend/p7-cxx20.cpp
+++ clang/test/CXX/class/class.friend/p7-cxx20.cpp
@@ -48,10 +48,10 @@
class Z {
friend void z(){};
};
-// CHECK-MOD: |-CXXRecordDecl {{.*}} <./header.h:2:1, line:4:1> line:2:7 in M.<global> hidden class A definition
-// CHECK-MOD: | |-CXXRecordDecl {{.*}} <col:1, col:7> col:7 in M.<global> hidden implicit class A
-// CHECK-MOD-NEXT: | `-FriendDecl {{.*}} <line:3:3, col:19> col:15 in M.<global>
-// CHECK-MOD-NEXT: | `-FunctionDecl {{.*}} parent {{.*}} <col:3, col:19> col:15 in M.<global> hidden a 'void ()' implicit-inline
+// CHECK-MOD: |-CXXRecordDecl {{.*}} <./header.h:2:1, line:4:1> line:2:7 in M.<global> hidden class A{{( ModuleDiscardable)?}} definition
+// CHECK-MOD: | |-CXXRecordDecl {{.*}} <col:1, col:7> col:7 in M.<global> hidden implicit class A{{( ModuleDiscardable)?}}
+// CHECK-MOD-NEXT: | `-FriendDecl {{.*}} <line:3:3, col:19> col:15 in M.<global>{{( ModuleDiscardable)?}}
+// CHECK-MOD-NEXT: | `-FunctionDecl {{.*}} parent {{.*}} <col:3, col:19> col:15 in M.<global> hidden a 'void ()'{{( ModuleDiscardable)?}} implicit-inline
// CHECK-MOD: `-CXXRecordDecl {{.*}} <module.cpp:6:1, line:8:1> line:6:7 in M hidden class Z{{( ReachableWhenImported)?}} definition
// CHECK-MOD: |-CXXRecordDecl {{.*}} <col:1, col:7> col:7 in M hidden implicit class Z{{( ReachableWhenImported)?}}
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,9 +29,8 @@
#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 {{missing '#include "foo.h"'; 'in_header' must be declared before it is used}}
+ // [email protected]:3 {{declaration here is not visible}}
global_module_fragment = 1; // expected-error {{missing '#include'; 'global_module_fragment' must be declared before it is used}}
// [email protected]:16 {{not visible}}
@@ -57,9 +56,8 @@
#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 {{missing '#include "foo.h"'; 'in_header' must be declared before it is used}}
+ // [email protected]:3 {{declaration here is not visible}}
global_module_fragment = 1; // expected-error {{missing '#include'; 'global_module_fragment' must be declared before it is used}}
// [email protected]:16 {{not visible}}
Index: clang/test/AST/ast-dump-decl.c
===================================================================
--- clang/test/AST/ast-dump-decl.c
+++ clang/test/AST/ast-dump-decl.c
@@ -1,16 +1,16 @@
// Test without serialization:
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-strict-prototypes -ast-dump -ast-dump-filter Test %s \
-// RUN: | FileCheck --strict-whitespace %s
+// RUN: | FileCheck --strict-whitespace %s -check-prefix CHECK-NOMODULE
//
// Test with serialization:
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-strict-prototypes -emit-pch -o %t %s
// RUN: %clang_cc1 -x c -triple x86_64-unknown-unknown -Wno-strict-prototypes -include-pch %t \
// RUN: -ast-dump-all -ast-dump-filter Test /dev/null \
// RUN: | sed -e "s/ <undeserialized declarations>//" -e "s/ imported//" \
-// RUN: | FileCheck --strict-whitespace %s
+// RUN: | FileCheck --strict-whitespace %s -check-prefix CHECK-NOMODULE
//
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-strict-prototypes -ast-dump %s \
-// RUN: | FileCheck -check-prefix CHECK-TU --strict-whitespace %s
+// RUN: | FileCheck -check-prefix CHECK-TU --strict-whitespace %s -check-prefix CHECK-NOMODULE
//
// RUN: %clang_cc1 -fmodules -fmodules-local-submodule-visibility -fmodule-name=X \
// RUN: -triple x86_64-unknown-unknown -Wno-strict-prototypes -fmodule-map-file=%S/Inputs/module.modulemap \
@@ -166,13 +166,16 @@
// CHECK-MODULE: FieldDecl{{.*}} TestFieldDeclPrivate 'int' __module_private__
int TestVarDecl;
-// CHECK: VarDecl{{.*}} TestVarDecl 'int'
+// CHECK-NOMODULE: VarDecl{{.*}} TestVarDecl 'int'
+// CHECK-MODULE: VarDecl{{.*}} TestVarDecl 'int' VisibleWhenImported
extern int TestVarDeclSC;
-// CHECK: VarDecl{{.*}} TestVarDeclSC 'int' extern
+// CHECK-NOMODULE: VarDecl{{.*}} TestVarDeclSC 'int' extern
+// CHECK-MODULE: VarDecl{{.*}} TestVarDeclSC 'int' extern VisibleWhenImported
__thread int TestVarDeclThread;
-// CHECK: VarDecl{{.*}} TestVarDeclThread 'int' tls{{$}}
+// CHECK-NOMODULE: VarDecl{{.*}} TestVarDeclThread 'int' tls{{$}}
+// CHECK-MODULE: VarDecl{{.*}} TestVarDeclThread 'int' tls{{$}} VisibleWhenImported
__module_private__ int TestVarDeclPrivate;
// CHECK-MODULE: VarDecl{{.*}} TestVarDeclPrivate 'int' __module_private__
Index: clang/lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- clang/lib/Serialization/ASTReaderDecl.cpp
+++ clang/lib/Serialization/ASTReaderDecl.cpp
@@ -622,6 +622,7 @@
case Decl::ModuleOwnershipKind::VisibleWhenImported:
case Decl::ModuleOwnershipKind::ReachableWhenImported:
case Decl::ModuleOwnershipKind::ModulePrivate:
+ case Decl::ModuleOwnershipKind::ModuleDiscardable:
break;
}
@@ -629,9 +630,10 @@
// Store the owning submodule ID in the declaration.
D->setOwningModuleID(SubmoduleID);
- if (ModulePrivate) {
- // Module-private declarations are never visible, so there is no work to
- // do.
+ if (ModulePrivate ||
+ ModuleOwnership == Decl::ModuleOwnershipKind::ModuleDiscardable) {
+ // Module-private and unreachable declarations are never visible, so
+ // there is no work to do.
} else if (Reader.getContext().getLangOpts().ModulesLocalVisibility) {
// If local visibility is being tracked, this declaration will become
// hidden and visible as the owning module does.
@@ -642,6 +644,8 @@
else
Reader.HiddenNamesMap[Owner].push_back(D);
}
+ } else if (ModuleOwnership == Decl::ModuleOwnershipKind::ModuleDiscardable) {
+ D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModuleDiscardable);
} else if (ModulePrivate) {
D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModulePrivate);
}
Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1011,7 +1011,7 @@
SemaRef.inferGslPointerAttribute(Typedef);
Typedef->setAccess(D->getAccess());
- Typedef->setReferenced(D->isReferenced());
+ SemaRef.setDeclReferenced(Typedef, D->isReferenced());
return Typedef;
}
@@ -1076,7 +1076,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;
}
@@ -5196,8 +5196,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
@@ -2768,7 +2768,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.
@@ -3283,7 +3283,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
@@ -1519,7 +1519,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);
@@ -3151,7 +3151,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
@@ -12,10 +12,14 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/DeclFriend.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/SemaInternal.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Format.h"
+
using namespace clang;
using namespace sema;
@@ -83,8 +87,6 @@
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);
@@ -96,8 +98,10 @@
// provide declarations that are attached to the global module and usable
// within the module unit.
//
- // So the declations in the global module shouldn't be visible by default.
- TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ReachableWhenImported);
+ // 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.
+ TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModuleDiscardable);
TU->setLocalOwningModule(GlobalModule);
// FIXME: Consider creating an explicit representation of this declaration.
@@ -909,6 +913,16 @@
// no declarations (transitively), in which case it's ill-formed.
diagExportedUnnamedDecl(*this, UnnamedDeclKind::Context, Child,
BlockStart);
+ } else if (getLangOpts().CPlusPlusModules && GlobalModuleFragment) {
+ // An export must be in module purview, so mark any used GMF content.
+ if (auto *USD = dyn_cast<UsingShadowDecl>(Child)) {
+ NamedDecl *Target = USD->getUnderlyingDecl();
+ if (Target->hasOwningModule() &&
+ Target->getOwningModule()->isGlobalModule()) {
+ // Mark the target of the using declaration as reachable.
+ markGMFDeclsReachableFrom(Target);
+ }
+ }
}
if (auto *FD = dyn_cast<FunctionDecl>(Child)) {
// [dcl.inline]/7
@@ -968,3 +982,213 @@
return M->isSubModuleOf(CurrentModuleUnit->getTopLevelModule());
}
+
+// A helper to process a used type to find GMF reachable decls which it uses.
+
+void Sema::findGMFReachableDeclsForType(const QualType &Q) {
+ // If we have a reference, mark the underlying type.
+ auto QR = Q.getNonReferenceType();
+ auto UT = QR.getDesugaredType(Context);
+ const Type *T = UT.getTypePtr();
+ assert(T && "missing type pointer?");
+ // Do not try to process it if incomplete (allow it to be visited again).
+ if (T->isIncompleteType())
+ return;
+ if (auto *AT = dyn_cast<AutoType>(T)) {
+ if (AT->isDeduced() && !AT->getDeducedType().isNull())
+ findGMFReachableDeclsForType(AT->getDeducedType());
+ // Allow a revisit to this, in the event that the deduced type is unknown
+ return;
+ }
+
+ // Only visit each Type once.
+ if (!GMFTypesVisited.insert(T).second)
+ return;
+ // Return as early as possible if this is not an entity we would need to mark
+ // but typedefs of built-in types need to be caught first (since the typedef
+ // could be in the GMF).
+ if (auto *TD = dyn_cast<TypedefType>(T)) {
+ markGMFDeclsReachableFrom(TD->getDecl());
+ } else if (T->isBuiltinType()) {
+ return;
+ } else if (auto *PT = dyn_cast<PointerType>(T)) {
+ return;
+ } else if (auto *ET = dyn_cast<EnumType>(T)) {
+ markGMFDeclsReachableFrom(ET->getDecl());
+ } else if (auto *TST = dyn_cast<TemplateSpecializationType>(T)) {
+ if (auto *RT = TST->getAsCXXRecordDecl())
+ markGMFDeclsReachableFrom(RT);
+ TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl();
+ markGMFDeclsReachableFrom(TD);
+ } else if (auto *RD = T->getAsCXXRecordDecl()) {
+ markGMFDeclsReachableFrom(RD);
+ } else if (auto *TP = dyn_cast<TemplateTypeParmType>(T)) {
+ markGMFDeclsReachableFrom(TP->getDecl());
+ } else if (auto *DN = dyn_cast<DependentNameType>(T)) {
+ return;
+ } else if (auto *ST = dyn_cast<SubstTemplateTypeParmType>(T)) {
+ findGMFReachableDeclsForType(ST->getReplacementType());
+ } else if (auto *ET = dyn_cast<ElaboratedType>(T)) {
+ findGMFReachableDeclsForType(ET->getNamedType());
+ } else if (auto *PE = dyn_cast<PackExpansionType>(T)) {
+ findGMFReachableDeclsForType(PE->getPattern());
+ } else if (auto *AT = dyn_cast<ArrayType>(T)) {
+ findGMFReachableDeclsForType(AT->getElementType());
+ } else if (auto *DT = dyn_cast<DecltypeType>(T)) {
+ if (!DT->getUnderlyingType().isNull())
+ findGMFReachableDeclsForType(DT->getUnderlyingType());
+ } else if (auto *UT = dyn_cast<UnaryTransformType>(T)) {
+ if (!UT->getUnderlyingType().isNull())
+ findGMFReachableDeclsForType(UT->getUnderlyingType());
+ } else if (auto *MT = dyn_cast<MemberPointerType>(T)) {
+ findGMFReachableDeclsForType(QualType(MT->getClass(), 0));
+ } else if (auto *DT = dyn_cast<DependentTemplateSpecializationType>(T)) {
+ auto *NNS = DT->getQualifier();
+ if (NNS && NNS->getKind() == NestedNameSpecifier::TypeSpec)
+ findGMFReachableDeclsForType(QualType(NNS->getAsType(), 0));
+ } else {
+ llvm::dbgs() << llvm::format("unhandled type: %p ", T);
+ T->dump();
+ }
+}
+
+// A helper to recurse through a stmt/expr tree finding expressions with
+// content that makes GMF decls reachable.
+
+void Sema::findGMFReachableDeclExprs(clang::Stmt *S) {
+
+ if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S)) {
+ markGMFDeclsReachableFrom(DR->getFoundDecl());
+ } else if (DependentScopeDeclRefExpr *DS =
+ dyn_cast<DependentScopeDeclRefExpr>(S)) {
+ auto *NNS = DS->getQualifier();
+ if (NNS && NNS->getKind() == NestedNameSpecifier::TypeSpec)
+ findGMFReachableDeclsForType(QualType(NNS->getAsType(), 0));
+ } else if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(S)) {
+ for (auto *D : ULE->decls())
+ markGMFDeclsReachableFrom(D);
+ } else if (DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
+ if (DS->isSingleDecl())
+ markGMFDeclsReachableFrom(DS->getSingleDecl());
+ else {
+ for (auto *D : DS->decls())
+ markGMFDeclsReachableFrom(D);
+ }
+ }
+
+ // Recurse into sub-expressions.
+ for (auto *CH : S->children()) {
+ if (CH)
+ findGMFReachableDeclExprs(CH);
+ }
+}
+
+// Starting from decl Orig (which is marked as reachable/visible if it is in
+// the GMF and currently marked as ModuleDiscardable), process other decls
+// reachable from this one and mark them too.
+
+void Sema::markGMFDeclsReachableFrom(Decl *Orig) {
+
+ // Do not alter the ownership kind unless it is ModuleDiscardable.
+ if (!Orig->isModuleDiscardable())
+ return;
+
+ // Only visit each Decl once, when the state is changed.
+ assert(Orig->getOwningModule() && Orig->getOwningModule()->isGlobalModule() &&
+ "should not have a discardable decl outside the GMF");
+ Orig->setModuleOwnershipKind(
+ Decl::ModuleOwnershipKind::ReachableWhenImported);
+
+ // Now process the decl to determine if any dependent decls should also be
+ // updated.
+
+ if (auto FT = dyn_cast<FunctionTemplateDecl>(Orig)) {
+ markGMFDeclsReachableFrom(FT->getTemplatedDecl());
+ for (auto *SP : FT->specializations())
+ markGMFDeclsReachableFrom(SP);
+ for (auto *TA : *FT->getTemplateParameters())
+ markGMFDeclsReachableFrom(TA);
+ return;
+ }
+
+ if (auto *FD = dyn_cast<FunctionDecl>(Orig)) {
+ findGMFReachableDeclsForType(FD->getReturnType());
+ for (ParmVarDecl *P : FD->parameters())
+ markGMFDeclsReachableFrom(P);
+ const FunctionDecl *BodyDecl;
+ if (auto *S = FD->getBody(BodyDecl))
+ findGMFReachableDeclExprs(S);
+ return;
+ }
+
+ if (auto TS = dyn_cast<ClassTemplateSpecializationDecl>(Orig)) {
+ markGMFDeclsReachableFrom(TS->getSpecializedTemplate());
+ if (!TS->isCompleteDefinition())
+ return;
+ for (auto B : TS->bases())
+ findGMFReachableDeclsForType(B.getType());
+ return;
+ }
+
+ if (auto CD = dyn_cast<ClassTemplateDecl>(Orig)) {
+ markGMFDeclsReachableFrom(CD->getTemplatedDecl());
+ for (auto *SP : CD->specializations())
+ markGMFDeclsReachableFrom(SP);
+ for (auto *TA : *CD->getTemplateParameters())
+ markGMFDeclsReachableFrom(TA);
+ return;
+ }
+
+ if (auto *RD = dyn_cast<CXXRecordDecl>(Orig)) {
+ if (!RD->isCompleteDefinition())
+ return;
+ DeclContext *DC = Decl::castToDeclContext(RD);
+ for (auto *D : DC->decls())
+ markGMFDeclsReachableFrom(D);
+ for (auto B : RD->bases())
+ findGMFReachableDeclsForType(B.getType());
+ return;
+ }
+
+ if (auto *TTA = dyn_cast<TemplateTypeParmDecl>(Orig)) {
+ if (TTA->hasDefaultArgument())
+ findGMFReachableDeclsForType(TTA->getDefaultArgument());
+ return;
+ }
+
+ if (auto *PD = dyn_cast<ParmVarDecl>(Orig)) {
+ findGMFReachableDeclsForType(PD->getOriginalType());
+ if (PD->hasUninstantiatedDefaultArg())
+ // FIXME: maybe we should walk the expression here.
+ return;
+ if (auto *E = PD->getDefaultArg())
+ findGMFReachableDeclExprs(E);
+ return;
+ }
+
+ if (auto *VD = dyn_cast<VarDecl>(Orig)) {
+ findGMFReachableDeclsForType(VD->getType());
+ if (VD->hasInit())
+ findGMFReachableDeclExprs(VD->getInit());
+ return;
+ }
+
+ if (auto *FD = dyn_cast<FieldDecl>(Orig)) {
+ findGMFReachableDeclsForType(FD->getType());
+ if (auto *Init = FD->getInClassInitializer())
+ findGMFReachableDeclExprs(Init);
+ return;
+ }
+
+ if (auto *FD = dyn_cast<FriendDecl>(Orig)) {
+ if (auto *DD = FD->getFriendDecl())
+ markGMFDeclsReachableFrom(DD);
+ return;
+ }
+
+ if (auto *ED = dyn_cast<EnumConstantDecl>(Orig)) {
+ if (auto *E = dyn_cast<EnumDecl>(ED->getDeclContext()))
+ markGMFDeclsReachableFrom(E);
+ return;
+ }
+}
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);
@@ -1984,7 +1984,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"
@@ -15852,7 +15853,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));
@@ -17947,7 +17948,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.
@@ -18180,7 +18181,7 @@
}
}
- Func->markUsed(Context);
+ markDeclUsed(Func, Context);
}
}
@@ -18251,7 +18252,7 @@
}
}
- Var->markUsed(SemaRef.Context);
+ SemaRef.markDeclUsed(Var, SemaRef.Context);
}
void Sema::MarkCaptureUsedInEnclosingContext(VarDecl *Capture,
@@ -19444,7 +19445,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;
@@ -19744,7 +19745,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
@@ -8815,7 +8815,7 @@
return;
}
FD->setBody(Body.get());
- FD->markUsed(Context);
+ markDeclUsed(FD, Context);
}
// The exception specification is needed because we are defining the
@@ -13529,7 +13529,7 @@
? Constructor->getEndLoc()
: Constructor->getLocation();
Constructor->setBody(new (Context) CompoundStmt(Loc));
- Constructor->markUsed(Context);
+ markDeclUsed(Constructor, Context);
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(Constructor);
@@ -13708,7 +13708,7 @@
}
Constructor->setBody(new (Context) CompoundStmt(InitLoc));
- Constructor->markUsed(Context);
+ markDeclUsed(Constructor, Context);
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(Constructor);
@@ -13819,7 +13819,7 @@
? Destructor->getEndLoc()
: Destructor->getLocation();
Destructor->setBody(new (Context) CompoundStmt(Loc));
- Destructor->markUsed(Context);
+ markDeclUsed(Destructor, Context);
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(Destructor);
@@ -14674,7 +14674,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);
@@ -15044,7 +15044,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);
@@ -15188,7 +15188,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()) {
@@ -15314,7 +15314,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()) {
@@ -15365,7 +15365,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()));
@@ -15377,7 +15377,7 @@
Stmt *Return = BuildReturnStmt(Conv->getLocation(), FunctionRef).get();
Conv->setBody(CompoundStmt::Create(Context, Return, FPOptionsOverride(),
Conv->getLocation(), Conv->getLocation()));
- Conv->markUsed(Context);
+ markDeclUsed(Conv, Context);
Conv->setReferenced();
if (ASTMutationListener *L = getASTMutationListener()) {
@@ -15432,7 +15432,7 @@
Stmt *ReturnS = Return.get();
Conv->setBody(CompoundStmt::Create(Context, ReturnS, FPOptionsOverride(),
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
@@ -2011,7 +2011,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
@@ -4246,7 +4246,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.
@@ -4662,7 +4662,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/Sema/Sema.cpp
===================================================================
--- clang/lib/Sema/Sema.cpp
+++ clang/lib/Sema/Sema.cpp
@@ -1100,6 +1100,9 @@
assert(DelayedDiagnostics.getCurrentPool() == nullptr
&& "reached end of translation unit with a pool attached?");
+ // We have finished checking if decls in a GMF need to be made reachable.
+ GMFTypesVisited.clear();
+
// If code completion is enabled, don't perform any end-of-translation-unit
// work.
if (PP.isCodeCompletionEnabled())
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"
@@ -57,6 +58,29 @@
llvm_unreachable("Decl that isn't part of DeclNodes.inc!");
}
+static void dumpModuleOwnership(raw_ostream &OS, const Decl *D) {
+ switch (D->getModuleOwnershipKind()) {
+ case Decl::ModuleOwnershipKind::Unowned:
+ // OS << " Unowned";
+ break;
+ case Decl::ModuleOwnershipKind::Visible:
+ OS << " Visible";
+ break;
+ case Decl::ModuleOwnershipKind::VisibleWhenImported:
+ OS << " VisibleWhenImported";
+ break;
+ case Decl::ModuleOwnershipKind::ReachableWhenImported:
+ OS << " ReachableWhenImported";
+ break;
+ case Decl::ModuleOwnershipKind::ModulePrivate:
+ OS << " __module_private__";
+ break;
+ case Decl::ModuleOwnershipKind::ModuleDiscardable:
+ OS << " ModuleDiscardable";
+ break;
+ }
+}
+
TextNodeDumper::TextNodeDumper(raw_ostream &OS, const ASTContext &Context,
bool ShowColors)
: TextTreeStructure(OS, ShowColors), OS(OS), ShowColors(ShowColors),
@@ -1623,8 +1647,7 @@
void TextNodeDumper::VisitTypedefDecl(const TypedefDecl *D) {
dumpName(D);
dumpType(D->getUnderlyingType());
- if (D->isModulePrivate())
- OS << " __module_private__";
+ dumpModuleOwnership(OS, D);
}
void TextNodeDumper::VisitEnumDecl(const EnumDecl *D) {
@@ -1635,8 +1658,7 @@
OS << " struct";
}
dumpName(D);
- if (D->isModulePrivate())
- OS << " __module_private__";
+ dumpModuleOwnership(OS, D);
if (D->isFixed())
dumpType(D->getIntegerType());
}
@@ -1644,8 +1666,7 @@
void TextNodeDumper::VisitRecordDecl(const RecordDecl *D) {
OS << ' ' << D->getKindName();
dumpName(D);
- if (D->isModulePrivate())
- OS << " __module_private__";
+ dumpModuleOwnership(OS, D);
if (D->isCompleteDefinition())
OS << " definition";
}
@@ -1674,8 +1695,7 @@
OS << " inline";
if (D->isVirtualAsWritten())
OS << " virtual";
- if (D->isModulePrivate())
- OS << " __module_private__";
+ dumpModuleOwnership(OS, D);
if (D->isPure())
OS << " pure";
@@ -1755,8 +1775,7 @@
dumpType(D->getType());
if (D->isMutable())
OS << " mutable";
- if (D->isModulePrivate())
- OS << " __module_private__";
+ dumpModuleOwnership(OS, D);
}
void TextNodeDumper::VisitVarDecl(const VarDecl *D) {
@@ -1775,8 +1794,7 @@
OS << " tls_dynamic";
break;
}
- if (D->isModulePrivate())
- OS << " __module_private__";
+ dumpModuleOwnership(OS, D);
if (D->isNRVOVariable())
OS << " nrvo";
if (D->isInline())
@@ -1952,6 +1970,7 @@
{
ColorScope Color(OS, ShowColors, DeclKindNameColor);
OS << "DefinitionData";
+ dumpModuleOwnership(OS, D);
}
#define FLAG(fn, name) \
if (D->fn()) \
@@ -1991,6 +2010,7 @@
FLAG(hasConstexprDefaultConstructor, constexpr);
FLAG(needsImplicitDefaultConstructor, needs_implicit);
FLAG(defaultedDefaultConstructorIsConstexpr, defaulted_is_constexpr);
+ dumpModuleOwnership(OS, D);
});
AddChild([=] {
@@ -2009,6 +2029,7 @@
if (!D->needsOverloadResolutionForCopyConstructor())
FLAG(defaultedCopyConstructorIsDeleted, defaulted_is_deleted);
FLAG(implicitCopyConstructorHasConstParam, implicit_has_const_param);
+ dumpModuleOwnership(OS, D);
});
AddChild([=] {
@@ -2026,6 +2047,7 @@
needs_overload_resolution);
if (!D->needsOverloadResolutionForMoveConstructor())
FLAG(defaultedMoveConstructorIsDeleted, defaulted_is_deleted);
+ dumpModuleOwnership(OS, D);
});
AddChild([=] {
@@ -2041,6 +2063,7 @@
FLAG(needsImplicitCopyAssignment, needs_implicit);
FLAG(needsOverloadResolutionForCopyAssignment, needs_overload_resolution);
FLAG(implicitCopyAssignmentHasConstParam, implicit_has_const_param);
+ dumpModuleOwnership(OS, D);
});
AddChild([=] {
@@ -2055,6 +2078,7 @@
FLAG(hasUserDeclaredMoveAssignment, user_declared);
FLAG(needsImplicitMoveAssignment, needs_implicit);
FLAG(needsOverloadResolutionForMoveAssignment, needs_overload_resolution);
+ dumpModuleOwnership(OS, D);
});
AddChild([=] {
@@ -2072,6 +2096,7 @@
FLAG(needsOverloadResolutionForDestructor, needs_overload_resolution);
if (!D->needsOverloadResolutionForDestructor())
FLAG(defaultedDestructorIsDeleted, defaulted_is_deleted);
+ dumpModuleOwnership(OS, D);
});
});
@@ -2083,20 +2108,24 @@
dumpType(I.getType());
if (I.isPackExpansion())
OS << "...";
+ dumpModuleOwnership(OS, D);
});
}
}
void TextNodeDumper::VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) {
dumpName(D);
+ dumpModuleOwnership(OS, D);
}
void TextNodeDumper::VisitClassTemplateDecl(const ClassTemplateDecl *D) {
dumpName(D);
+ dumpModuleOwnership(OS, D);
}
void TextNodeDumper::VisitVarTemplateDecl(const VarTemplateDecl *D) {
dumpName(D);
+ dumpModuleOwnership(OS, D);
}
void TextNodeDumper::VisitBuiltinTemplateDecl(const BuiltinTemplateDecl *D) {
@@ -2120,6 +2149,7 @@
if (D->isParameterPack())
OS << " ...";
dumpName(D);
+ dumpModuleOwnership(OS, D);
}
void TextNodeDumper::VisitNonTypeTemplateParmDecl(
@@ -2129,6 +2159,7 @@
if (D->isParameterPack())
OS << " ...";
dumpName(D);
+ dumpModuleOwnership(OS, D);
}
void TextNodeDumper::VisitTemplateTemplateParmDecl(
@@ -2137,6 +2168,7 @@
if (D->isParameterPack())
OS << " ...";
dumpName(D);
+ dumpModuleOwnership(OS, D);
}
void TextNodeDumper::VisitUsingDecl(const UsingDecl *D) {
@@ -2144,6 +2176,7 @@
if (D->getQualifier())
D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
OS << D->getDeclName();
+ dumpModuleOwnership(OS, D);
}
void TextNodeDumper::VisitUsingEnumDecl(const UsingEnumDecl *D) {
@@ -2171,6 +2204,7 @@
void TextNodeDumper::VisitUsingShadowDecl(const UsingShadowDecl *D) {
OS << ' ';
dumpBareDeclRef(D->getTargetDecl());
+ dumpModuleOwnership(OS, D);
}
void TextNodeDumper::VisitConstructorUsingShadowDecl(
@@ -2217,6 +2251,7 @@
void TextNodeDumper::VisitFriendDecl(const FriendDecl *D) {
if (TypeSourceInfo *T = D->getFriendType())
dumpType(T->getType());
+ dumpModuleOwnership(OS, D);
}
void TextNodeDumper::VisitObjCIvarDecl(const ObjCIvarDecl *D) {
Index: clang/lib/AST/Decl.cpp
===================================================================
--- clang/lib/AST/Decl.cpp
+++ clang/lib/AST/Decl.cpp
@@ -593,6 +593,7 @@
case Decl::ModuleOwnershipKind::Unowned:
case Decl::ModuleOwnershipKind::ReachableWhenImported:
case Decl::ModuleOwnershipKind::ModulePrivate:
+ case Decl::ModuleOwnershipKind::ModuleDiscardable:
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
@@ -2295,7 +2295,55 @@
bool isAcceptableSlow(const NamedDecl *D, AcceptableKind Kind);
+ /// When checking for Global Module Fragment decls that need to be made
+ /// reachable we also need to consider the types used. This set is used to
+ /// ensure that we only visit each type once.
+ llvm::SmallPtrSet<const clang::Type *, 32> GMFTypesVisited;
+
+ /// Examine a type, unwrapping any decls that might be in the GMF.
+ void findGMFReachableDeclsForType(const QualType &Q);
+
+ /// Walk a statement/expression tree looking for cases that require GMF decls
+ /// to be made reachable.
+ void findGMFReachableDeclExprs(clang::Stmt *S);
+
+ /// Starting from a decl D mark any additional decls in the GMF this makes
+ /// reachable.
+ void markGMFDeclsReachableFrom(Decl *D);
+
+ // We have marked some decl as used (or referenced) and therefore (if we are
+ // in a module purview, and there is a GMF) we need to see if that use or
+ // reference requires us to make GMF decl(s) reachable.
+ void handleGMFDeclsReachableFrom(Decl *D) {
+ // Try to use an early exit for the cases we do not need to consider.
+ if (!getLangOpts().CPlusPlusModules || !GlobalModuleFragment ||
+ !isCurrentModulePurview())
+ return;
+
+ // We only need to make the decls reachable, not visible.
+ markGMFDeclsReachableFrom(D);
+ }
+
public:
+ /// To implement C++20 GMF elision semantics, we initially mark decls in the
+ /// Global Module Fragment as "ModuleDiscardable". If the decl is then used
+ /// within the module purview, we reset that to visible.
+ void setDeclIsUsed(Decl *D) {
+ D->setIsUsed();
+ handleGMFDeclsReachableFrom(D);
+ }
+
+ /// Likewise when the decl is marked used and notifies mutation listeners.
+ void markDeclUsed(Decl *D, ASTContext &C) {
+ D->markUsed(C);
+ handleGMFDeclsReachableFrom(D);
+ }
+
+ void setDeclReferenced(Decl *D, bool R = true) {
+ D->setReferenced(R);
+ handleGMFDeclsReachableFrom(D);
+ }
+
/// Get the module unit whose scope we are currently within.
Module *getCurrentModule() const {
return ModuleScopes.empty() ? nullptr : ModuleScopes.back().Module;
Index: clang/include/clang/AST/DeclBase.h
===================================================================
--- clang/include/clang/AST/DeclBase.h
+++ clang/include/clang/AST/DeclBase.h
@@ -232,9 +232,12 @@
/// This declaration has an owning module, but is only visible to
/// lookups that occur within that module.
- /// The discarded declarations in global module fragment belongs
- /// to this group too.
- ModulePrivate
+ ModulePrivate,
+
+ /// This declaration is part of a Global Module Fragment, it is permitted
+ /// to discard it and therefore it is not reachable or visible to importers
+ /// of the named module of which the GMF is part.
+ ModuleDiscardable
};
protected:
@@ -602,6 +605,12 @@
void setReferenced(bool R = true) { Referenced = R; }
+ /// Whether this declaration should be retained if it is used.
+ bool isModuleDiscardable() const {
+ return getModuleOwnershipKind() ==
+ Decl::ModuleOwnershipKind::ModuleDiscardable;
+ }
+
/// Whether this declaration is a top-level declaration (function,
/// global variable, etc.) that is lexically inside an objc container
/// definition.
@@ -641,9 +650,10 @@
return getModuleOwnershipKind() > ModuleOwnershipKind::VisibleWhenImported;
}
- /// FIXME: Implement discarding declarations actually in global module
- /// fragment. See [module.global.frag]p3,4 for details.
- bool isDiscardedInGlobalModuleFragment() const { return false; }
+ /// See [module.global.frag]p3,4 for details.
+ bool isDiscardedInGlobalModuleFragment() const {
+ return getModuleOwnershipKind() == ModuleOwnershipKind::ModuleDiscardable;
+ }
/// Return true if this declaration has an attribute which acts as
/// definition of the entity, such as 'alias' or 'ifunc'.
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits