@@ -34,18 +34,43 @@ class ClangDeclRefFinder
3434 return true ;
3535 }
3636};
37+
38+ // If any (re)declaration of `decl` contains executable code, returns that
39+ // redeclaration; otherwise, returns nullptr.
40+ // In the case of a function, executable code is contained in the function
41+ // definition. In the case of a variable, executable code can be contained in
42+ // the initializer of the variable.
43+ clang::Decl *getDeclWithExecutableCode (clang::Decl *decl) {
44+ if (auto fd = dyn_cast<clang::FunctionDecl>(decl)) {
45+ const clang::FunctionDecl *definition;
46+ if (fd->hasBody (definition)) {
47+ return const_cast <clang::FunctionDecl *>(definition);
48+ }
49+ } else if (auto vd = dyn_cast<clang::VarDecl>(decl)) {
50+ clang::VarDecl *initializingDecl = vd->getInitializingDeclaration ();
51+ if (initializingDecl) {
52+ return initializingDecl;
53+ }
54+ }
55+
56+ return nullptr ;
57+ }
58+
3759} // end anonymous namespace
3860
3961void IRGenModule::emitClangDecl (const clang::Decl *decl) {
40- auto valueDecl = dyn_cast<clang::ValueDecl>(decl);
41- if (!valueDecl || valueDecl->isExternallyVisible ()) {
62+ // Ignore this decl if we've seen it before.
63+ if (!GlobalClangDecls.insert (decl->getCanonicalDecl ()).second )
64+ return ;
65+
66+ // Fast path for the case where `decl` doesn't contain executable code, so it
67+ // can't reference any other declarations that we would need to emit.
68+ if (getDeclWithExecutableCode (const_cast <clang::Decl *>(decl)) == nullptr ) {
4269 ClangCodeGen->HandleTopLevelDecl (
4370 clang::DeclGroupRef (const_cast <clang::Decl*>(decl)));
4471 return ;
4572 }
4673
47- if (!GlobalClangDecls.insert (decl->getCanonicalDecl ()).second )
48- return ;
4974 SmallVector<const clang::Decl *, 8 > stack;
5075 stack.push_back (decl);
5176
@@ -69,13 +94,15 @@ void IRGenModule::emitClangDecl(const clang::Decl *decl) {
6994
7095 while (!stack.empty ()) {
7196 auto *next = const_cast <clang::Decl *>(stack.pop_back_val ());
72- if (auto fn = dyn_cast<clang::FunctionDecl>(next)) {
73- const clang::FunctionDecl *definition;
74- if (fn->hasBody (definition)) {
75- refFinder.TraverseDecl (const_cast <clang::FunctionDecl *>(definition));
76- next = const_cast <clang::FunctionDecl *>(definition);
77- }
97+ if (clang::Decl *executableDecl = getDeclWithExecutableCode (next)) {
98+ refFinder.TraverseDecl (executableDecl);
99+ next = executableDecl;
78100 }
101+
102+ if (auto var = dyn_cast<clang::VarDecl>(next))
103+ if (!var->isFileVarDecl ())
104+ continue ;
105+
79106 ClangCodeGen->HandleTopLevelDecl (clang::DeclGroupRef (next));
80107 }
81108}
0 commit comments