Skip to content
4 changes: 2 additions & 2 deletions include/swift/AST/Attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -3126,8 +3126,8 @@ class ExternAttr : public DeclAttribute {
}

/// Returns the C name of the given declaration.
/// \p forDecl is the func decl that the attribute belongs to.
StringRef getCName(const FuncDecl *forDecl) const;
/// \p forDecl is the decl that the attribute belongs to.
StringRef getCName(const ValueDecl *forDecl) const;

/// Find an ExternAttr with the given kind in the given DeclAttributes.
static const ExternAttr *find(const DeclAttributes &attrs, ExternKind kind);
Expand Down
4 changes: 4 additions & 0 deletions include/swift/AST/DiagnosticsIRGen.def
Original file line number Diff line number Diff line change
Expand Up @@ -117,5 +117,9 @@ NOTE(maybe_missing_parameter, none,
"%select{constraint|parameter}0",
(bool, const clang::NamedDecl *))

ERROR(ir_function_redefinition_external,none,
"multiple definitions of symbol '%0'",
(StringRef))

#define UNDEFINE_DIAGNOSTIC_MACROS
#include "DefineDiagnosticMacros.h"
2 changes: 1 addition & 1 deletion include/swift/SIL/SILDeclRef.h
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ struct SILDeclRef {

/// If the symbol has a specific name for use at the LLVM IR level,
/// produce that name. This may be different than the mangled name in SIL.
std::optional<StringRef> getAsmName() const;
std::optional<std::string> getAsmName() const;

/// True if the SILDeclRef references a function.
bool isFunc() const {
Expand Down
2 changes: 1 addition & 1 deletion include/swift/SIL/SILFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -1430,7 +1430,7 @@ class SILFunction

/// Return custom assembler name, otherwise empty.
StringRef asmName() const { return AsmName; }
void setAsmName(StringRef value) { AsmName = value; }
void setAsmName(StringRef value);

/// Return custom section name if @section was used, otherwise empty
StringRef section() const { return Section; }
Expand Down
2 changes: 1 addition & 1 deletion include/swift/SIL/SILGlobalVariable.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ class SILGlobalVariable

/// Return custom assembler name, otherwise empty.
StringRef asmName() const { return AsmName; }
void setAsmName(StringRef value) { AsmName = value; }
void setAsmName(StringRef value);

/// Return custom section name if @section was used, otherwise empty
StringRef section() const { return Section; }
Expand Down
17 changes: 15 additions & 2 deletions include/swift/SIL/SILModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,10 @@ class SILModule {
llvm::StringMap<SILFunction *> FunctionTable;
llvm::StringMap<SILFunction *> ZombieFunctionTable;

/// Lookup table for SIL functions by their asmnames, for those that
/// have them.
llvm::StringMap<SILFunction *> FunctionByAsmNameTable;

/// The list of SILFunctions in the module.
FunctionListType functions;

Expand Down Expand Up @@ -310,6 +314,9 @@ class SILModule {
/// Lookup table for SIL Global Variables.
llvm::StringMap<SILGlobalVariable *> GlobalVariableMap;

/// Lookup table for SIL Global Variables, indexed by their asmnames.
llvm::StringMap<SILGlobalVariable *> GlobalVariableByAsmNameMap;

/// The list of SILGlobalVariables in the module.
GlobalListType silGlobals;

Expand Down Expand Up @@ -822,14 +829,20 @@ class SILModule {
/// Look for a global variable by name.
///
/// \return null if this module has no such global variable
SILGlobalVariable *lookUpGlobalVariable(StringRef name) const {
SILGlobalVariable *lookUpGlobalVariable(StringRef name,
bool byAsmName = false) const {
if (byAsmName)
return GlobalVariableByAsmNameMap.lookup(name);

return GlobalVariableMap.lookup(name);
}

/// Look for a function by name.
///
/// \return null if this module has no such function
SILFunction *lookUpFunction(StringRef name) const {
SILFunction *lookUpFunction(StringRef name, bool byAsmName = false) const {
if (byAsmName)
return FunctionByAsmNameTable.lookup(name);
return FunctionTable.lookup(name);
}

Expand Down
6 changes: 4 additions & 2 deletions include/swift/Serialization/SerializedSILLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,10 @@ class SerializedSILLoader {

SILFunction *lookupSILFunction(SILFunction *Callee, bool onlyUpdateLinkage);
SILFunction *lookupSILFunction(StringRef Name,
std::optional<SILLinkage> linkage);
SILGlobalVariable *lookupSILGlobalVariable(StringRef Name);
std::optional<SILLinkage> linkage,
bool byAsmName = false);
SILGlobalVariable *lookupSILGlobalVariable(StringRef Name,
bool byAsmName = false);
bool hasSILFunction(StringRef Name,
std::optional<SILLinkage> linkage = std::nullopt);
SILVTable *lookupVTable(const ClassDecl *C);
Expand Down
13 changes: 13 additions & 0 deletions lib/AST/ASTMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,19 @@ void ASTMangler::beginManglingWithAutoDiffOriginalFunction(
beginManglingClangDecl(typedefType->getDecl());
return;
}

if (auto *EA = ExternAttr::find(afd->getAttrs(), ExternKind::C)) {
beginManglingWithoutPrefix();
appendOperator(EA->getCName(afd));
return;
}

if (afd->getAttrs().hasAttribute<CDeclAttr>()) {
beginManglingWithoutPrefix();
appendOperator(afd->getCDeclName());
return;
}

beginMangling();
if (auto *cd = dyn_cast<ConstructorDecl>(afd))
appendConstructorEntity(cd, /*isAllocating*/ !cd->isConvenienceInit());
Expand Down
4 changes: 2 additions & 2 deletions lib/AST/Attr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3273,11 +3273,11 @@ bool MacroRoleAttr::hasNameKind(MacroIntroducedDeclNameKind kind) const {
}) != getNames().end();
}

StringRef ExternAttr::getCName(const FuncDecl *D) const {
StringRef ExternAttr::getCName(const ValueDecl *D) const {
if (auto cName = this->Name)
return cName.value();
// If no name was specified, fall back on the Swift base name without mangling.
// Base name is always available and non-empty for FuncDecl.
// Base name is always available and non-empty for functions and variables.
return D->getBaseIdentifier().str();
}

Expand Down
93 changes: 75 additions & 18 deletions lib/ClangImporter/SwiftDeclSynthesizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2066,34 +2066,91 @@ clang::CXXMethodDecl *SwiftDeclSynthesizer::synthesizeCXXForwardingMethod(

// Create a new method in the derived class that calls the base method.
clang::DeclarationName name = method->getNameInfo().getName();
std::string newName;
llvm::raw_string_ostream os(newName);
bool useExistingName = false;
if (name.isIdentifier()) {
std::string newName;
llvm::raw_string_ostream os(newName);
os << (forwardingMethodKind == ForwardingMethodKind::Virtual
? "__synthesizedVirtualCall_"
: "__synthesizedBaseCall_")
<< name.getAsIdentifierInfo()->getName();
name = clang::DeclarationName(
&ImporterImpl.getClangPreprocessor().getIdentifierTable().get(
os.str()));
} else if (name.getCXXOverloadedOperator() == clang::OO_Subscript) {
name = clang::DeclarationName(
&ImporterImpl.getClangPreprocessor().getIdentifierTable().get(
(forwardingMethodKind == ForwardingMethodKind::Virtual
} else {
switch (auto op = name.getCXXOverloadedOperator()) {
case clang::OO_Subscript:
os << (forwardingMethodKind == ForwardingMethodKind::Virtual
? "__synthesizedVirtualCall_operatorSubscript"
: "__synthesizedBaseCall_operatorSubscript")));
} else if (name.getCXXOverloadedOperator() == clang::OO_Star) {
name = clang::DeclarationName(
&ImporterImpl.getClangPreprocessor().getIdentifierTable().get(
(forwardingMethodKind == ForwardingMethodKind::Virtual
: "__synthesizedBaseCall_operatorSubscript");
if (forceConstQualifier)
os << "C";
break;

case clang::OO_Star:
os << (forwardingMethodKind == ForwardingMethodKind::Virtual
? "__synthesizedVirtualCall_operatorStar"
: "__synthesizedBaseCall_operatorStar")));
} else if (name.getCXXOverloadedOperator() == clang::OO_Call) {
assert(forwardingMethodKind != ForwardingMethodKind::Virtual);
: "__synthesizedBaseCall_operatorStar");
if (forceConstQualifier)
os << "C";
break;

case clang::OO_Call:
assert(forwardingMethodKind != ForwardingMethodKind::Virtual);
os << "__synthesizedBaseCall_operatorCall";
if (forceConstQualifier)
os << "C";
break;

case clang::OO_Plus:
case clang::OO_Minus:
case clang::OO_Slash:
case clang::OO_PlusEqual:
case clang::OO_MinusEqual:
case clang::OO_StarEqual:
case clang::OO_SlashEqual:
case clang::OO_Percent:
case clang::OO_Caret:
case clang::OO_Amp:
case clang::OO_Pipe:
case clang::OO_Tilde:
case clang::OO_Exclaim:
case clang::OO_Less:
case clang::OO_Greater:
case clang::OO_LessLess:
case clang::OO_GreaterGreater:
case clang::OO_EqualEqual:
case clang::OO_PlusPlus:
case clang::OO_ExclaimEqual:
case clang::OO_LessEqual:
case clang::OO_GreaterEqual:
case clang::OO_AmpAmp:
case clang::OO_PipePipe:
os << importer::getOperatorName(ImporterImpl.SwiftContext, op).str();
break;

default:
useExistingName = true;
break;
}
}

if (!useExistingName) {
// The created method is inside the derived class already. If that's
// different from the base class, also include the base class in the
// mangling to keep this separate from other similar functions cloned from
// other base classes.
if (derivedClass != baseClass) {
os << "_";
std::unique_ptr<clang::ItaniumMangleContext> mangler{
clang::ItaniumMangleContext::create(clangCtx, clangCtx.getDiagnostics())};
auto derivedType = clangCtx.getTypeDeclType(baseClass)
.getCanonicalType();
mangler->mangleCanonicalTypeName(derivedType, os);
}

name = clang::DeclarationName(
&ImporterImpl.getClangPreprocessor().getIdentifierTable().get(
"__synthesizedBaseCall_operatorCall"));
os.str()));
}

auto methodType = method->getType();
// Check if we need to drop the reference from the return type
// of the new method. This is needed when a synthesized `operator []`
Expand Down
21 changes: 15 additions & 6 deletions lib/IRGen/IRGenSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ class IRGenSILFunction :
llvm::DenseMap<SILInstruction *, llvm::SmallVector<StackPackAlloc, 2>>
StackPackAllocs;

IRGenSILFunction(IRGenModule &IGM, SILFunction *f);
IRGenSILFunction(IRGenModule &IGM, SILFunction *f, llvm::Function *llvmF);
~IRGenSILFunction();

/// Generate IR for the SIL Function.
Expand Down Expand Up @@ -1887,10 +1887,9 @@ llvm::Value *LoweredValue::getSingletonExplosion(IRGenFunction &IGF,
llvm_unreachable("bad kind");
}

IRGenSILFunction::IRGenSILFunction(IRGenModule &IGM, SILFunction *f)
: IRGenFunction(IGM,
IGM.getAddrOfSILFunction(f, ForDefinition,
f->isDynamicallyReplaceable()),
IRGenSILFunction::IRGenSILFunction(IRGenModule &IGM, SILFunction *f,
llvm::Function *llvmF)
: IRGenFunction(IGM, llvmF,
f->isPerformanceConstraint(),
f->getOptimizationMode(), f->getDebugScope(),
f->getLocation()),
Expand Down Expand Up @@ -2558,7 +2557,17 @@ void IRGenModule::emitSILFunction(SILFunction *f) {
noteUseOfMetadataByCXXInterop(IRGen, f, TypeExpansionContext(*f));

PrettyStackTraceSILFunction stackTrace("emitting IR", f);
IRGenSILFunction(*this, f).emitSILFunction();

// Get the LLVM function we will emit. If it has already been defined, error.
auto llvmF = getAddrOfSILFunction(f, ForDefinition,
f->isDynamicallyReplaceable());
if (!llvmF->empty()) {
auto &diags = Context.Diags;
diags.diagnose(f->getLocation().getSourceLoc(), diag::ir_function_redefinition_external, llvmF->getName());
return;
}

IRGenSILFunction(*this, f, llvmF).emitSILFunction();
}

void IRGenSILFunction::emitSILFunction() {
Expand Down
63 changes: 27 additions & 36 deletions lib/SIL/IR/SILDeclRef.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1386,18 +1386,6 @@ std::string SILDeclRef::mangle(ManglingKind MKind) const {
silConfig);
}

// As a special case, Clang functions and globals don't get mangled at all
// - except \c objc_direct decls.
if (hasDecl() && !isDefaultArgGenerator()) {
if (getDecl()->getClangDecl()) {
if (!isForeignToNativeThunk() && !isNativeToForeignThunk()) {
auto clangMangling = mangleClangDecl(getDecl(), isForeign);
if (!clangMangling.empty())
return clangMangling;
}
}
}

// Mangle prespecializations.
if (getSpecializedSignature()) {
SILDeclRef nonSpecializedDeclRef = *this;
Expand Down Expand Up @@ -1443,23 +1431,6 @@ std::string SILDeclRef::mangle(ManglingKind MKind) const {
return NameA->Name.str();
}

// Use a given cdecl name for native-to-foreign thunks. Don't do this
// for functions that only have a C entrypoint.
if (getDecl()->getAttrs().hasAttribute<CDeclAttr>() &&
!(getDecl()->hasOnlyCEntryPoint() &&
!getDecl()->getImplementedObjCDecl())) {
if (isNativeToForeignThunk() || isForeign) {
// If this is an @implementation @_cdecl, mangle it like the clang
// function it implements.
if (auto objcInterface = getDecl()->getImplementedObjCDecl()) {
auto clangMangling = mangleClangDecl(objcInterface, isForeign);
if (!clangMangling.empty())
return clangMangling;
}
return getDecl()->getCDeclName().str();
}
}

if (SKind == ASTMangler::SymbolKind::DistributedThunk) {
return mangler.mangleDistributedThunk(cast<FuncDecl>(getDecl()));
}
Expand Down Expand Up @@ -1547,13 +1518,33 @@ std::string SILDeclRef::mangle(ManglingKind MKind) const {
llvm_unreachable("bad entity kind!");
}

std::optional<StringRef> SILDeclRef::getAsmName() const {
if (isForeign && isFunc()) {
auto func = getFuncDecl();
if (auto *EA = ExternAttr::find(func->getAttrs(), ExternKind::C))
return EA->getCName(func);
if (func->hasOnlyCEntryPoint() && !func->getImplementedObjCDecl())
return func->getCDeclName();
std::optional<std::string> SILDeclRef::getAsmName() const {
if (isAutoDiffDerivativeFunction())
return std::nullopt;

if (hasDecl() && !isDefaultArgGenerator() &&
(getDecl()->getClangDecl() || getDecl()->getImplementedObjCDecl())) {
// If there is a Clang declaration, use its mangled name.
if (isNativeToForeignThunk() || isForeign) {
auto decl = getDecl();
auto hasClangDecl = decl->getClangDecl()
? decl : decl->getImplementedObjCDecl();
auto clangMangling = mangleClangDecl(hasClangDecl, isForeign);
if (!clangMangling.empty())
return clangMangling;
}
}

if (isForeign && hasDecl()) {
// @_extern(c)
auto decl = getDecl();
if (auto *EA = ExternAttr::find(decl->getAttrs(), ExternKind::C))
if (auto VD = dyn_cast<ValueDecl>(decl))
return std::string(EA->getCName(VD));

// @c/@_cdecl
if (decl->getAttrs().hasAttribute<CDeclAttr>())
return std::string(decl->getCDeclName());
}

return std::nullopt;
Expand Down
Loading