mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[Macros] Handle macro overloading.
Allow more than one macro plugin to introduce a macro with the same name, and let the constraint solver figure out which one to call. Also eliminates a potential use-after-free if we somehow find additional compiler plugins to load after having expanded a macro.
This commit is contained in:
@@ -352,12 +352,6 @@ public:
|
|||||||
llvm::SmallPtrSet<DerivativeAttr *, 1>>
|
llvm::SmallPtrSet<DerivativeAttr *, 1>>
|
||||||
DerivativeAttrs;
|
DerivativeAttrs;
|
||||||
|
|
||||||
/// Cache of compiler plugins keyed by their name.
|
|
||||||
llvm::StringMap<CompilerPlugin> LoadedPlugins;
|
|
||||||
|
|
||||||
/// Cache of loaded symbols.
|
|
||||||
llvm::StringMap<void *> LoadedSymbols;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// The current generation number, which reflects the number of
|
/// The current generation number, which reflects the number of
|
||||||
/// times that external modules have been loaded.
|
/// times that external modules have been loaded.
|
||||||
@@ -1452,8 +1446,11 @@ public:
|
|||||||
/// The declared interface type of Builtin.TheTupleType.
|
/// The declared interface type of Builtin.TheTupleType.
|
||||||
BuiltinTupleType *getBuiltinTupleType();
|
BuiltinTupleType *getBuiltinTupleType();
|
||||||
|
|
||||||
/// Finds the loaded compiler plugin given its name.
|
/// Finds the loaded compiler plugins with the given name.
|
||||||
CompilerPlugin *getLoadedPlugin(StringRef name);
|
TinyPtrVector<CompilerPlugin *> getLoadedPlugins(StringRef name);
|
||||||
|
|
||||||
|
/// Add a loaded plugin with the given name.
|
||||||
|
void addLoadedPlugin(StringRef name, CompilerPlugin *plugin);
|
||||||
|
|
||||||
/// Finds the address of the given symbol. If `libraryHandleHint` is non-null,
|
/// Finds the address of the given symbol. If `libraryHandleHint` is non-null,
|
||||||
/// search within the library.
|
/// search within the library.
|
||||||
|
|||||||
@@ -515,6 +515,15 @@ struct ASTContext::Implementation {
|
|||||||
|
|
||||||
llvm::StringMap<OptionSet<SearchPathKind>> SearchPathsSet;
|
llvm::StringMap<OptionSet<SearchPathKind>> SearchPathsSet;
|
||||||
|
|
||||||
|
/// Cache of compiler plugins keyed by their name.
|
||||||
|
///
|
||||||
|
/// Names can be overloaded, so there can be multiple plugins with the same
|
||||||
|
/// name.
|
||||||
|
llvm::StringMap<TinyPtrVector<CompilerPlugin*>> LoadedPlugins;
|
||||||
|
|
||||||
|
/// Cache of loaded symbols.
|
||||||
|
llvm::StringMap<void *> LoadedSymbols;
|
||||||
|
|
||||||
/// The permanent arena.
|
/// The permanent arena.
|
||||||
Arena Permanent;
|
Arena Permanent;
|
||||||
|
|
||||||
@@ -579,6 +588,12 @@ ASTContext::Implementation::Implementation()
|
|||||||
ASTContext::Implementation::~Implementation() {
|
ASTContext::Implementation::~Implementation() {
|
||||||
for (auto &cleanup : Cleanups)
|
for (auto &cleanup : Cleanups)
|
||||||
cleanup();
|
cleanup();
|
||||||
|
|
||||||
|
for (const auto &pluginsByName : LoadedPlugins) {
|
||||||
|
for (auto plugin : pluginsByName.second) {
|
||||||
|
delete plugin;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstraintCheckerArenaRAII::
|
ConstraintCheckerArenaRAII::
|
||||||
@@ -6047,16 +6062,21 @@ BuiltinTupleType *ASTContext::getBuiltinTupleType() {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
CompilerPlugin *ASTContext::getLoadedPlugin(StringRef name) {
|
TinyPtrVector<CompilerPlugin *> ASTContext::getLoadedPlugins(StringRef name) {
|
||||||
auto lookup = LoadedPlugins.find(name);
|
auto &loadedPlugins = getImpl().LoadedPlugins;
|
||||||
if (lookup == LoadedPlugins.end())
|
auto lookup = loadedPlugins.find(name);
|
||||||
return nullptr;
|
if (lookup == loadedPlugins.end())
|
||||||
return &lookup->second;
|
return { };
|
||||||
|
return lookup->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASTContext::addLoadedPlugin(StringRef name, CompilerPlugin *plugin) {
|
||||||
|
getImpl().LoadedPlugins[name].push_back(plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *ASTContext::getAddressOfSymbol(const char *name,
|
void *ASTContext::getAddressOfSymbol(const char *name,
|
||||||
void *libraryHandleHint) {
|
void *libraryHandleHint) {
|
||||||
auto lookup = LoadedSymbols.try_emplace(name, nullptr);
|
auto lookup = getImpl().LoadedSymbols.try_emplace(name, nullptr);
|
||||||
void *&address = lookup.first->getValue();
|
void *&address = lookup.first->getValue();
|
||||||
#if !defined(_WIN32)
|
#if !defined(_WIN32)
|
||||||
if (lookup.second) {
|
if (lookup.second) {
|
||||||
|
|||||||
@@ -188,9 +188,9 @@ void ASTContext::loadCompilerPlugins() {
|
|||||||
swift_ASTGen_getMacroTypes(getter, &metatypesAddress, &metatypeCount);
|
swift_ASTGen_getMacroTypes(getter, &metatypesAddress, &metatypeCount);
|
||||||
ArrayRef<const void *> metatypes(metatypesAddress, metatypeCount);
|
ArrayRef<const void *> metatypes(metatypesAddress, metatypeCount);
|
||||||
for (const void *metatype : metatypes) {
|
for (const void *metatype : metatypes) {
|
||||||
CompilerPlugin plugin(metatype, lib, *this);
|
auto plugin = new CompilerPlugin(metatype, lib, *this);
|
||||||
auto name = plugin.getName();
|
auto name = plugin->getName();
|
||||||
LoadedPlugins.try_emplace(name, std::move(plugin));
|
addLoadedPlugin(name, plugin);
|
||||||
}
|
}
|
||||||
free(const_cast<void *>((const void *)metatypes.data()));
|
free(const_cast<void *>((const void *)metatypes.data()));
|
||||||
#endif // SWIFT_SWIFT_PARSER
|
#endif // SWIFT_SWIFT_PARSER
|
||||||
|
|||||||
@@ -317,7 +317,7 @@ ArrayRef<MacroDecl *> MacroLookupRequest::evaluate(
|
|||||||
// Look for a loaded plugin based on the macro name.
|
// Look for a loaded plugin based on the macro name.
|
||||||
// FIXME: This API needs to be able to return multiple plugins, because
|
// FIXME: This API needs to be able to return multiple plugins, because
|
||||||
// several plugins could export a macro with the same name.
|
// several plugins could export a macro with the same name.
|
||||||
if (auto *plugin = ctx.getLoadedPlugin(macroName.str())) {
|
for (auto plugin: ctx.getLoadedPlugins(macroName.str())) {
|
||||||
if (auto pluginMacro = createPluginMacro(mod, macroName, plugin)) {
|
if (auto pluginMacro = createPluginMacro(mod, macroName, plugin)) {
|
||||||
macros.push_back(pluginMacro);
|
macros.push_back(pluginMacro);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -180,10 +180,95 @@ struct ColorLiteralMacro: _CompilerPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct HSVColorLiteralMacro: _CompilerPlugin {
|
||||||
|
static func _name() -> (UnsafePointer<UInt8>, count: Int) {
|
||||||
|
var name = "customColorLiteral"
|
||||||
|
return name.withUTF8 { buffer in
|
||||||
|
let result = UnsafeMutablePointer<UInt8>.allocate(capacity: buffer.count)
|
||||||
|
result.initialize(from: buffer.baseAddress!, count: buffer.count)
|
||||||
|
return (UnsafePointer(result), count: buffer.count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func _genericSignature() -> (UnsafePointer<UInt8>?, count: Int) {
|
||||||
|
var genSig = "<T>"
|
||||||
|
return genSig.withUTF8 { buffer in
|
||||||
|
let result = UnsafeMutablePointer<UInt8>.allocate(capacity: buffer.count)
|
||||||
|
result.initialize(from: buffer.baseAddress!, count: buffer.count)
|
||||||
|
return (UnsafePointer(result), count: buffer.count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func _typeSignature() -> (UnsafePointer<UInt8>, count: Int) {
|
||||||
|
var typeSig =
|
||||||
|
"""
|
||||||
|
(
|
||||||
|
hue hue: Float, saturation saturation: Float, value value: Float
|
||||||
|
) -> T
|
||||||
|
"""
|
||||||
|
return typeSig.withUTF8 { buffer in
|
||||||
|
let result = UnsafeMutablePointer<UInt8>.allocate(capacity: buffer.count)
|
||||||
|
result.initialize(from: buffer.baseAddress!, count: buffer.count)
|
||||||
|
return (UnsafePointer(result), count: buffer.count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func _owningModule() -> (UnsafePointer<UInt8>, count: Int) {
|
||||||
|
var swiftModule = "Swift"
|
||||||
|
return swiftModule.withUTF8 { buffer in
|
||||||
|
let result = UnsafeMutablePointer<UInt8>.allocate(capacity: buffer.count)
|
||||||
|
result.initialize(from: buffer.baseAddress!, count: buffer.count)
|
||||||
|
return (UnsafePointer(result), count: buffer.count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func _supplementalSignatureModules() -> (UnsafePointer<UInt8>, count: Int) {
|
||||||
|
var nothing = ""
|
||||||
|
return nothing.withUTF8 { buffer in
|
||||||
|
let result = UnsafeMutablePointer<UInt8>.allocate(capacity: buffer.count)
|
||||||
|
result.initialize(from: buffer.baseAddress!, count: buffer.count)
|
||||||
|
return (UnsafePointer(result), count: buffer.count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func _kind() -> _CompilerPluginKind {
|
||||||
|
.expressionMacro
|
||||||
|
}
|
||||||
|
|
||||||
|
static func _rewrite(
|
||||||
|
targetModuleName: UnsafePointer<UInt8>,
|
||||||
|
targetModuleNameCount: Int,
|
||||||
|
filePath: UnsafePointer<UInt8>,
|
||||||
|
filePathCount: Int,
|
||||||
|
sourceFileText: UnsafePointer<UInt8>,
|
||||||
|
sourceFileTextCount: Int,
|
||||||
|
localSourceText: UnsafePointer<UInt8>,
|
||||||
|
localSourceTextCount: Int
|
||||||
|
) -> (UnsafePointer<UInt8>?, count: Int) {
|
||||||
|
let meeTextBuffer = UnsafeBufferPointer(
|
||||||
|
start: localSourceText, count: localSourceTextCount)
|
||||||
|
let meeText = String(decoding: meeTextBuffer, as: UTF8.self)
|
||||||
|
let prefix = "#customColorLiteral(hue:"
|
||||||
|
guard meeText.starts(with: prefix), meeText.last == ")" else {
|
||||||
|
return (nil, 0)
|
||||||
|
}
|
||||||
|
let expr = meeText.dropFirst(prefix.count).dropLast()
|
||||||
|
var resultString = ".init(_colorLiteralHue:\(expr))"
|
||||||
|
return resultString.withUTF8 { buffer in
|
||||||
|
let result = UnsafeMutableBufferPointer<UInt8>.allocate(
|
||||||
|
capacity: buffer.count + 1)
|
||||||
|
_ = result.initialize(from: buffer)
|
||||||
|
result[buffer.count] = 0
|
||||||
|
return (UnsafePointer(result.baseAddress), buffer.count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public var allMacros: [Any.Type] {
|
public var allMacros: [Any.Type] {
|
||||||
[
|
[
|
||||||
StringifyMacro.self,
|
StringifyMacro.self,
|
||||||
ColorLiteralMacro.self
|
ColorLiteralMacro.self,
|
||||||
|
HSVColorLiteralMacro.self
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,12 @@ let _ = #customStringify(["a", "b", "c"] + ["d", "e", "f"])
|
|||||||
|
|
||||||
struct MyColor: _ExpressibleByColorLiteral {
|
struct MyColor: _ExpressibleByColorLiteral {
|
||||||
init(_colorLiteralRed red: Float, green: Float, blue: Float, alpha: Float) { }
|
init(_colorLiteralRed red: Float, green: Float, blue: Float, alpha: Float) { }
|
||||||
|
init(_colorLiteralHue hue: Float, saturation: Float, value: Float) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CHECK: (macro_expansion_expr type='MyColor' {{.*}} name=customColorLiteral
|
||||||
let _: MyColor = #customColorLiteral(red: 0.5, green: 0.5, blue: 0.2, alpha: 0.9)
|
let _: MyColor = #customColorLiteral(red: 0.5, green: 0.5, blue: 0.2, alpha: 0.9)
|
||||||
|
|
||||||
|
// CHECK: (macro_expansion_expr type='MyColor' {{.*}} name=customColorLiteral
|
||||||
|
let _: MyColor = #customColorLiteral(hue: 0.5, saturation: 0.5, value: 0.2)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user