Skip to content

Commit dccaa8f

Browse files
committed
diagnose duplicated @_cdecl and @_silgen_name function names
Prints a regular error instead of crashing. The check is done in SILGen, because it's simple. We could also do it earlier, but I don't see a strong reason for this. rdar://75950093
1 parent e4f4b89 commit dccaa8f

File tree

5 files changed

+42
-4
lines changed

5 files changed

+42
-4
lines changed

include/swift/AST/DiagnosticsSIL.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ ERROR(bridging_objcbridgeable_broken,none,
4343
"broken definition of '_ObjectiveCBridgeable' protocol: missing %0",
4444
(DeclName))
4545

46+
ERROR(sil_function_redefinition,none,
47+
"multiple definitions of symbol '%0'",
48+
(StringRef))
49+
4650
ERROR(invalid_sil_builtin,none,
4751
"INTERNAL ERROR: invalid use of builtin: %0",
4852
(StringRef))

lib/SIL/IR/SILFunctionBuilder.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,14 @@ SILFunction *SILFunctionBuilder::getOrCreateFunction(
164164
SILLinkage linkage = constant.getLinkage(forDefinition);
165165

166166
if (auto fn = mod.lookUpFunction(nameTmp)) {
167-
assert(fn->getLoweredFunctionType() == constantType);
168-
assert(fn->getLinkage() == linkage ||
167+
// During SILGen (where the module's SIL stage is Raw), there might be
168+
// mismatches between the type or linkage. This can happen, when two
169+
// functions are mistakenly mapped to the same name (e.g. with @_cdecl).
170+
// We want to issue a regular error in this case and not crash with an
171+
// assert.
172+
assert(mod.getStage() == SILStage::Raw ||
173+
fn->getLoweredFunctionType() == constantType);
174+
assert(mod.getStage() == SILStage::Raw || fn->getLinkage() == linkage ||
169175
(forDefinition == ForDefinition_t::NotForDefinition &&
170176
fn->getLinkage() ==
171177
constant.getLinkage(ForDefinition_t::ForDefinition)));

lib/SILGen/SILGen.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -756,6 +756,12 @@ void SILGenModule::visitFuncDecl(FuncDecl *fd) { emitFunction(fd); }
756756

757757
void SILGenModule::emitFunctionDefinition(SILDeclRef constant, SILFunction *f) {
758758

759+
if (!f->empty()) {
760+
diagnose(constant.getAsRegularLocation(), diag::sil_function_redefinition,
761+
f->getName());
762+
return;
763+
}
764+
759765
if (constant.isForeignToNativeThunk()) {
760766
f->setThunk(IsThunk);
761767
if (constant.asForeign().isClangGenerated())
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// RUN: %target-swift-emit-silgen %s -o /dev/null -verify
2+
3+
@_silgen_name("foo")
4+
func a(_ x: Int) -> Int {
5+
return x
6+
}
7+
8+
@_silgen_name("foo")
9+
func b(_ x: Int) -> Int { // expected-error {{multiple definitions of symbol 'foo'}}
10+
return x
11+
}
12+
13+
@_cdecl("bar")
14+
func c(_ x: Int) -> Int {
15+
return x
16+
}
17+
18+
@_cdecl("bar")
19+
func d(_ x: Int) -> Int { // expected-error {{multiple definitions of symbol 'bar'}}
20+
return x
21+
}

validation-test/compiler_crashers/28806-swift-silmodule-get-or-create-function.swift renamed to validation-test/compiler_crashers_fixed/28806-swift-silmodule-get-or-create-function.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@
66
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
77

88
// REQUIRES: asserts
9-
// RUN: not --crash %target-swift-frontend %s -emit-ir
10-
@_cdecl("main")func x(){}
9+
// RUN: %target-swift-frontend %s -emit-ir -o /dev/null -verify
10+
11+
@_cdecl("main")func x(){} // expected-error {{multiple definitions of symbol 'main'}}

0 commit comments

Comments
 (0)