@@ -34,18 +34,43 @@ class ClangDeclRefFinder
34
34
return true ;
35
35
}
36
36
};
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
+
37
59
} // end anonymous namespace
38
60
39
61
void 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 ) {
42
69
ClangCodeGen->HandleTopLevelDecl (
43
70
clang::DeclGroupRef (const_cast <clang::Decl*>(decl)));
44
71
return ;
45
72
}
46
73
47
- if (!GlobalClangDecls.insert (decl->getCanonicalDecl ()).second )
48
- return ;
49
74
SmallVector<const clang::Decl *, 8 > stack;
50
75
stack.push_back (decl);
51
76
@@ -69,13 +94,15 @@ void IRGenModule::emitClangDecl(const clang::Decl *decl) {
69
94
70
95
while (!stack.empty ()) {
71
96
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;
78
100
}
101
+
102
+ if (auto var = dyn_cast<clang::VarDecl>(next))
103
+ if (!var->isFileVarDecl ())
104
+ continue ;
105
+
79
106
ClangCodeGen->HandleTopLevelDecl (clang::DeclGroupRef (next));
80
107
}
81
108
}
0 commit comments