Skip to content

Commit 38dd7d8

Browse files
committed
[IRGen] Fix asserting local extern declarations.
emitClangDecl interacts with clang and LLVM to achieve C interop. On the LLVM side, CodeGenModule::EmitGlobal asserts if the decl eventually passed to it is not a "file scoped" via VarDecl::isFileVarDecl. LLVM currently asserts on local extern variables in C headers passed to Swift when the definition exists outside that header. To fix this, we need to ensure that we are only passing Decls that do not trip the assertion but not unduly limit local extern variables when the corresponding definition exists inside that header. We can do that fairly simply by checking for isFileVarDecl just before we hand-off to clang. When the definition for the local extern variable exists inside the header, isFileVarDecl is true, and if it exists elsewhere, it is false. This matches up with the assert expectation on the LLVM side exactly. This indirectly addresses #28968, since that contains the only part of the Swift stdlib that uses a local extern variable, but any header that is used with Swift that contains a local extern variable will cause the compiler to assert when built with assertions enabled.
1 parent 8f7b1d7 commit 38dd7d8

File tree

3 files changed

+36
-0
lines changed

3 files changed

+36
-0
lines changed

lib/IRGen/GenClangDecl.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,11 @@ void IRGenModule::emitClangDecl(const clang::Decl *decl) {
9898
refFinder.TraverseDecl(executableDecl);
9999
next = executableDecl;
100100
}
101+
102+
if (auto var = dyn_cast<clang::VarDecl>(next))
103+
if (!var->isFileVarDecl())
104+
continue;
105+
101106
ClangCodeGen->HandleTopLevelDecl(clang::DeclGroupRef(next));
102107
}
103108
}

test/IRGen/Inputs/local_extern.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
static inline int _no_prior_var() {
2+
extern int var;
3+
return var;
4+
}
5+
6+
static inline int _no_prior_func() {
7+
extern int func();
8+
return func();
9+
}
10+
11+
static int prior_var = 1;
12+
static inline int _prior_var() {
13+
extern int prior_var;
14+
return prior_var;
15+
}
16+
17+
static inline int prior_func() { return 1; }
18+
static inline int _prior_func() {
19+
extern int prior_func();
20+
return prior_func();
21+
}

test/IRGen/local_extern.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// RUN: %target-swift-frontend -import-objc-header %S/Inputs/local_extern.h %s -emit-ir | %FileCheck %s
2+
// CHECK: @var = external global i32
3+
// CHECK: @prior_var = internal global i32
4+
// CHECK: declare i32 @func
5+
// CHECK: define internal i32 @prior_func
6+
7+
print("\(_no_prior_var())")
8+
print("\(_no_prior_func())")
9+
print("\(_prior_var())")
10+
print("\(_prior_func())")

0 commit comments

Comments
 (0)