mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Merge remote-tracking branch 'origin/main' into rebranch
This commit is contained in:
@@ -28,16 +28,16 @@ private func log(_ message: @autoclosure () -> String) {
|
||||
/// Within safe swift code there shouldn't be any buffer overflows. But if the address
|
||||
/// of a stack variable is converted to an unsafe pointer, it's not in the control of
|
||||
/// the compiler anymore.
|
||||
/// This means, if there is any `address_to_pointer` instruction for an `alloc_stack`,
|
||||
/// such a function is marked for stack protection.
|
||||
/// Another case is `index_addr` for non-tail allocated memory. This pattern appears if
|
||||
/// pointer arithmetic is done with unsafe pointers in swift code.
|
||||
/// This means, if an `alloc_stack` ends up at an `address_to_pointer [stack_protection]`,
|
||||
/// the `alloc_stack`'s function is marked for stack protection.
|
||||
/// Another case is `index_addr [stack_protection]` for non-tail allocated memory. This
|
||||
/// pattern appears if pointer arithmetic is done with unsafe pointers in swift code.
|
||||
///
|
||||
/// If the origin of an unsafe pointer can only be tracked to a function argument, the
|
||||
/// pass tries to find the root stack allocation for such an argument by doing an
|
||||
/// inter-procedural analysis. If this is not possible, the fallback is to move the
|
||||
/// argument into a temporary `alloc_stack` and do the unsafe pointer operations on
|
||||
/// the temporary.
|
||||
/// inter-procedural analysis. If this is not possible and the `enableMoveInoutStackProtection`
|
||||
/// option is set, the fallback is to move the argument into a temporary `alloc_stack`
|
||||
/// and do the unsafe pointer operations on the temporary.
|
||||
let stackProtection = ModulePass(name: "stack-protection", {
|
||||
(context: ModulePassContext) in
|
||||
|
||||
@@ -45,7 +45,7 @@ let stackProtection = ModulePass(name: "stack-protection", {
|
||||
return
|
||||
}
|
||||
|
||||
var optimization = StackProtectionOptimization()
|
||||
var optimization = StackProtectionOptimization(enableMoveInout: context.options.enableMoveInoutStackProtection)
|
||||
optimization.processModule(context)
|
||||
})
|
||||
|
||||
@@ -60,13 +60,15 @@ let functionStackProtection = FunctionPass(name: "function-stack-protection", {
|
||||
return
|
||||
}
|
||||
|
||||
var optimization = StackProtectionOptimization()
|
||||
var optimization = StackProtectionOptimization(enableMoveInout: context.options.enableMoveInoutStackProtection)
|
||||
optimization.process(function: function, context)
|
||||
})
|
||||
|
||||
/// The optimization algorithm.
|
||||
private struct StackProtectionOptimization {
|
||||
|
||||
private let enableMoveInout: Bool
|
||||
|
||||
// The following members are nil/not used if this utility is used on function-level.
|
||||
|
||||
private var moduleContext: ModulePassContext?
|
||||
@@ -77,6 +79,10 @@ private struct StackProtectionOptimization {
|
||||
// are added to this array in `findOriginsInCallers`.
|
||||
private var needStackProtection: [Function] = []
|
||||
|
||||
init(enableMoveInout: Bool) {
|
||||
self.enableMoveInout = enableMoveInout
|
||||
}
|
||||
|
||||
/// The main entry point if running on module-level.
|
||||
mutating func processModule(_ moduleContext: ModulePassContext) {
|
||||
self.moduleContext = moduleContext
|
||||
@@ -147,6 +153,8 @@ private struct StackProtectionOptimization {
|
||||
case .yes:
|
||||
// For example:
|
||||
// %baseAddr = alloc_stack $T
|
||||
log("local: \(function.name) -- \(instruction)")
|
||||
|
||||
function.setNeedsStackProtection(context)
|
||||
|
||||
case .decidedInCaller(let arg):
|
||||
@@ -157,7 +165,7 @@ private struct StackProtectionOptimization {
|
||||
defer { worklist.deinitialize() }
|
||||
worklist.push(arg)
|
||||
|
||||
if !findOriginsInCallers(&worklist) {
|
||||
if findOriginsInCallers(&worklist) == NeedInsertMoves.yes {
|
||||
// We don't know the origin of the function argument. Therefore we need to do the
|
||||
// conservative default which is to move the value to a temporary stack location.
|
||||
if let beginAccess = scope {
|
||||
@@ -179,22 +187,19 @@ private struct StackProtectionOptimization {
|
||||
|
||||
// If the object is passed as an argument to its function, add those arguments
|
||||
// to the worklist.
|
||||
switch worklist.push(rootsOf: obj) {
|
||||
case .failed:
|
||||
// If we cannot find the roots, the object is most likely not stack allocated.
|
||||
return
|
||||
case .succeeded(let foundStackAlloc):
|
||||
let (_, foundStackAlloc) = worklist.push(rootsOf: obj)
|
||||
if foundStackAlloc {
|
||||
// The object is created by an `alloc_ref [stack]`.
|
||||
log("objectIfStackPromoted: \(function.name) -- \(instruction)")
|
||||
|
||||
function.setNeedsStackProtection(context)
|
||||
}
|
||||
}
|
||||
// In case the (potentially) stack allocated object is passed via an argument,
|
||||
// process the worklist as we do for indirect arguments (see above).
|
||||
// For example:
|
||||
// bb0(%0: $Class):
|
||||
// %baseAddr = ref_element_addr %0 : $Class, #Class.field
|
||||
if !findOriginsInCallers(&worklist),
|
||||
if findOriginsInCallers(&worklist) == NeedInsertMoves.yes,
|
||||
let beginAccess = scope {
|
||||
// We don't know the origin of the object. Therefore we need to do the
|
||||
// conservative default which is to move the value to a temporary stack location.
|
||||
@@ -207,14 +212,25 @@ private struct StackProtectionOptimization {
|
||||
}
|
||||
}
|
||||
|
||||
/// Return value of `findOriginsInCallers()`.
|
||||
enum NeedInsertMoves {
|
||||
// Not all call sites could be identified, and if moves are enabled (`enableMoveInout`)
|
||||
// the original argument should be moved to a temporary.
|
||||
case yes
|
||||
|
||||
// Either all call sites could be identified, which means that stack protection is done
|
||||
// in the callers, or moves are not enabled (`enableMoveInout` is false).
|
||||
case no
|
||||
}
|
||||
|
||||
/// Find all origins of function arguments in `worklist`.
|
||||
/// All functions, which allocate such an origin are added to `self.needStackProtection`.
|
||||
/// Returns true if all origins could be found and false, if there are unknown origins.
|
||||
private mutating func findOriginsInCallers(_ worklist: inout ArgumentWorklist) -> Bool {
|
||||
private mutating func findOriginsInCallers(_ worklist: inout ArgumentWorklist) -> NeedInsertMoves {
|
||||
|
||||
guard let moduleContext = moduleContext else {
|
||||
// Don't do any inter-procedural analysis when used on function-level.
|
||||
return false
|
||||
return enableMoveInout ? .yes : .no
|
||||
}
|
||||
|
||||
// Put the resulting functions into a temporary array, because we only add them to
|
||||
@@ -230,21 +246,25 @@ private struct StackProtectionOptimization {
|
||||
while let arg = worklist.pop() {
|
||||
let f = arg.function
|
||||
let uses = functionUses.getUses(of: f)
|
||||
if uses.hasUnknownUses {
|
||||
return false
|
||||
if uses.hasUnknownUses && enableMoveInout {
|
||||
return NeedInsertMoves.yes
|
||||
}
|
||||
|
||||
for useInst in uses {
|
||||
guard let fri = useInst as? FunctionRefInst else {
|
||||
return false
|
||||
if enableMoveInout {
|
||||
return NeedInsertMoves.yes
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
for functionRefUse in fri.uses {
|
||||
guard let apply = functionRefUse.instruction as? ApplySite else {
|
||||
return false
|
||||
guard let apply = functionRefUse.instruction as? ApplySite,
|
||||
let callerArgIdx = apply.callerArgIndex(calleeArgIndex: arg.index) else {
|
||||
if enableMoveInout {
|
||||
return NeedInsertMoves.yes
|
||||
}
|
||||
guard let callerArgIdx = apply.callerArgIndex(calleeArgIndex: arg.index) else {
|
||||
return false
|
||||
continue
|
||||
}
|
||||
let callerArg = apply.arguments[callerArgIdx]
|
||||
if callerArg.type.isAddress {
|
||||
@@ -252,6 +272,7 @@ private struct StackProtectionOptimization {
|
||||
switch callerArg.accessBase.isStackAllocated {
|
||||
case .yes:
|
||||
if !callerArg.function.needsStackProtection {
|
||||
log("alloc_stack in caller: \(callerArg.function.name) -- \(callerArg)")
|
||||
newFunctions.push(callerArg.function)
|
||||
}
|
||||
case .no:
|
||||
@@ -266,36 +287,38 @@ private struct StackProtectionOptimization {
|
||||
case .objectIfStackPromoted(let obj):
|
||||
// If the object is passed as an argument to its function,
|
||||
// add those arguments to the worklist.
|
||||
switch worklist.push(rootsOf: obj) {
|
||||
case .failed:
|
||||
return false
|
||||
case .succeeded(let foundStackAlloc):
|
||||
let (foundUnknownRoots, foundStackAlloc) = worklist.push(rootsOf: obj)
|
||||
if foundUnknownRoots && enableMoveInout {
|
||||
return NeedInsertMoves.yes
|
||||
}
|
||||
if foundStackAlloc && !obj.function.needsStackProtection {
|
||||
// The object is created by an `alloc_ref [stack]`.
|
||||
log("object in caller: \(obj.function.name) -- \(obj)")
|
||||
newFunctions.push(obj.function)
|
||||
}
|
||||
}
|
||||
case .unknown:
|
||||
return false
|
||||
if enableMoveInout {
|
||||
return NeedInsertMoves.yes
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// The argument is an object. If the object is itself passed as an argument
|
||||
// to its function, add those arguments to the worklist.
|
||||
switch worklist.push(rootsOf: callerArg) {
|
||||
case .failed:
|
||||
return false
|
||||
case .succeeded(let foundStackAlloc):
|
||||
let (foundUnknownRoots, foundStackAlloc) = worklist.push(rootsOf: callerArg)
|
||||
if foundUnknownRoots && enableMoveInout {
|
||||
return NeedInsertMoves.yes
|
||||
}
|
||||
if foundStackAlloc && !callerArg.function.needsStackProtection {
|
||||
// The object is created by an `alloc_ref [stack]`.
|
||||
log("object arg in caller: \(callerArg.function.name) -- \(callerArg)")
|
||||
newFunctions.push(callerArg.function)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
needStackProtection.append(contentsOf: newFunctions)
|
||||
return true
|
||||
return NeedInsertMoves.no
|
||||
}
|
||||
|
||||
/// Moves the value of an indirect argument to a temporary stack location, if possible.
|
||||
@@ -366,9 +389,16 @@ private struct StackProtectionOptimization {
|
||||
/// Worklist for inter-procedural analysis of function arguments.
|
||||
private struct ArgumentWorklist : ValueUseDefWalker {
|
||||
var walkUpCache = WalkerCache<SmallProjectionPath>()
|
||||
private var foundStackAlloc = false
|
||||
|
||||
// Used in `push(rootsOf:)`
|
||||
private var foundStackAlloc = false
|
||||
private var foundUnknownRoots = false
|
||||
|
||||
// Contains arguments which are already handled and don't need to be put into the worklist again.
|
||||
// Note that this cannot be a `ValueSet`, because argument can be from different functions.
|
||||
private var handled = Set<FunctionArgument>()
|
||||
|
||||
// The actual worklist.
|
||||
private var list: Stack<FunctionArgument>
|
||||
|
||||
init(_ context: PassContext) {
|
||||
@@ -385,21 +415,15 @@ private struct ArgumentWorklist : ValueUseDefWalker {
|
||||
}
|
||||
}
|
||||
|
||||
enum PushResult {
|
||||
case failed
|
||||
case succeeded(foundStackAlloc: Bool)
|
||||
}
|
||||
|
||||
/// Pushes all roots of `object`, which are function arguments, to the worklist.
|
||||
/// Returns `.succeeded(true)` if some of the roots are `alloc_ref [stack]` instructions.
|
||||
mutating func push(rootsOf object: Value) -> PushResult {
|
||||
/// If the returned `foundUnknownRoots` is true, it means that not all roots of `object` could
|
||||
/// be tracked to a function argument.
|
||||
/// If the returned `foundStackAlloc` than at least one found root is an `alloc_ref [stack]`.
|
||||
mutating func push(rootsOf object: Value) -> (foundUnknownRoots: Bool, foundStackAlloc: Bool) {
|
||||
foundStackAlloc = false
|
||||
switch walkUp(value: object, path: SmallProjectionPath(.anything)) {
|
||||
case .continueWalk:
|
||||
return .succeeded(foundStackAlloc: foundStackAlloc)
|
||||
case .abortWalk:
|
||||
return .failed
|
||||
}
|
||||
foundUnknownRoots = false
|
||||
_ = walkUp(value: object, path: SmallProjectionPath(.anything))
|
||||
return (foundUnknownRoots, foundStackAlloc)
|
||||
}
|
||||
|
||||
mutating func pop() -> FunctionArgument? {
|
||||
@@ -413,15 +437,12 @@ private struct ArgumentWorklist : ValueUseDefWalker {
|
||||
if ar.canAllocOnStack {
|
||||
foundStackAlloc = true
|
||||
}
|
||||
return .continueWalk
|
||||
case let arg as FunctionArgument:
|
||||
if handled.insert(arg).0 {
|
||||
list.push(arg)
|
||||
push(arg)
|
||||
default:
|
||||
foundUnknownRoots = true
|
||||
}
|
||||
return .continueWalk
|
||||
default:
|
||||
return .abortWalk
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -491,7 +512,6 @@ private extension Instruction {
|
||||
private extension Function {
|
||||
func setNeedsStackProtection(_ context: PassContext) {
|
||||
if !needsStackProtection {
|
||||
log("needs protection: \(name)")
|
||||
set(needStackProtection: true, context)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,4 +18,8 @@ struct Options {
|
||||
var enableStackProtection: Bool {
|
||||
SILOptions_enableStackProtection(_bridged) != 0
|
||||
}
|
||||
|
||||
var enableMoveInoutStackProtection: Bool {
|
||||
SILOptions_enableMoveInoutStackProtection(_bridged) != 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +52,11 @@ private:
|
||||
GenericSignature = 4,
|
||||
// static func _typeSignature(...) -> (UnsafePointer<UInt8>, count: Int)
|
||||
TypeSignature = 5,
|
||||
// static func _owningModule(...) -> (UnsafePointer<UInt8>, count: Int)
|
||||
OwningModule = 6,
|
||||
// static func _supplementalSignatureModules(...)
|
||||
// -> (UnsafePointer<UInt8>, count: Int)
|
||||
SupplementalSignatureModules = 7,
|
||||
};
|
||||
|
||||
/// The plugin type metadata.
|
||||
@@ -100,6 +105,14 @@ public:
|
||||
/// result string buffer.
|
||||
StringRef invokeTypeSignature() const;
|
||||
|
||||
/// Invoke the `_owningModule` method. The caller assumes ownership of the
|
||||
/// result string buffer.
|
||||
StringRef invokeOwningModule() const;
|
||||
|
||||
/// Invoke the `_supplementalSignatureModules` method. The caller assumes
|
||||
/// ownership of the result string buffer.
|
||||
StringRef invokeSupplementalSignatureModules() const;
|
||||
|
||||
StringRef getName() const {
|
||||
return name;
|
||||
}
|
||||
|
||||
86
include/swift/AST/Macro.h
Normal file
86
include/swift/AST/Macro.h
Normal file
@@ -0,0 +1,86 @@
|
||||
//===--- Macro.h - Swift Macro Definition -----------------------*- C++ -*-===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See https://swift.org/LICENSE.txt for license information
|
||||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the `Macro` type that describes a macro definition.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef SWIFT_AST_MACRO_H
|
||||
#define SWIFT_AST_MACRO_H
|
||||
|
||||
#include "swift/AST/ASTAllocated.h"
|
||||
#include "swift/AST/GenericSignature.h"
|
||||
#include "swift/AST/Identifier.h"
|
||||
#include "swift/AST/Type.h"
|
||||
|
||||
namespace swift {
|
||||
class ModuleDecl;
|
||||
|
||||
class Macro : public ASTAllocated<Macro> {
|
||||
public:
|
||||
/// The kind of macro, which determines how it can be used in source code.
|
||||
enum Kind: uint8_t {
|
||||
/// An expression macro.
|
||||
Expression,
|
||||
};
|
||||
|
||||
/// Describes how the macro is implemented.
|
||||
enum class ImplementationKind: uint8_t {
|
||||
/// The macro is built-in to the compiler, linked against the same
|
||||
/// underlying syntax tree libraries.
|
||||
Builtin,
|
||||
|
||||
/// The macro was defined in a compiler plugin.
|
||||
Plugin,
|
||||
};
|
||||
|
||||
/// The kind of macro.
|
||||
const Kind kind;
|
||||
|
||||
/// How the macro is implemented.
|
||||
const ImplementationKind implementationKind;
|
||||
|
||||
/// The name of the macro in the source, e.g., "stringify".
|
||||
const Identifier name;
|
||||
|
||||
/// The generic signature, used to describe the signature of macros that
|
||||
/// involve generic parameters.
|
||||
const GenericSignature genericSignature;
|
||||
|
||||
/// The type signature of the macro.
|
||||
const Type signature;
|
||||
|
||||
/// The module with which this macro is associated.
|
||||
ModuleDecl * const owningModule;
|
||||
|
||||
/// Supplemental modules that should be imported when
|
||||
const ArrayRef<ModuleDecl *> supplementalSignatureModules;
|
||||
|
||||
/// An opaque handle to the representation of the macro.
|
||||
void * const opaqueHandle;
|
||||
|
||||
public:
|
||||
Macro(
|
||||
Kind kind, ImplementationKind implementationKind, Identifier name,
|
||||
GenericSignature genericSignature, Type signature,
|
||||
ModuleDecl *owningModule,
|
||||
ArrayRef<ModuleDecl *> supplementalSignatureModules,
|
||||
void *opaqueHandle
|
||||
) : kind(kind), implementationKind(implementationKind), name(name),
|
||||
genericSignature(genericSignature), signature(signature),
|
||||
owningModule(owningModule),
|
||||
supplementalSignatureModules(supplementalSignatureModules),
|
||||
opaqueHandle(opaqueHandle) { }
|
||||
};
|
||||
}
|
||||
|
||||
#endif // SWIFT_AST_MACRO_H
|
||||
@@ -129,7 +129,11 @@ public:
|
||||
bool EnablePerformanceAnnotations = false;
|
||||
|
||||
/// Enables the emission of stack protectors in functions.
|
||||
bool EnableStackProtection = false;
|
||||
bool EnableStackProtection = true;
|
||||
|
||||
/// Like `EnableStackProtection` and also enables moving of values to
|
||||
/// temporaries for stack protection.
|
||||
bool EnableMoveInoutStackProtection = false;
|
||||
|
||||
/// Controls whether or not paranoid verification checks are run.
|
||||
bool VerifyAll = false;
|
||||
|
||||
@@ -45,6 +45,7 @@ class DefaultArgumentExpr;
|
||||
class DefaultArgumentType;
|
||||
class ClosureExpr;
|
||||
class GenericParamList;
|
||||
class Macro;
|
||||
class PrecedenceGroupDecl;
|
||||
class PropertyWrapperInitializerInfo;
|
||||
struct PropertyWrapperLValueness;
|
||||
@@ -3733,26 +3734,11 @@ public:
|
||||
bool isCached() const { return true; }
|
||||
};
|
||||
|
||||
|
||||
/// Retrieves the evaluation context of a macro with the given name.
|
||||
///
|
||||
/// The macro evaluation context is a user-defined generic signature and return
|
||||
/// type that serves as the "interface type" of references to the macro. The
|
||||
/// current implementation takes those pieces of syntax from the macro itself,
|
||||
/// then inserts them into a Swift struct that looks like
|
||||
///
|
||||
/// \code
|
||||
/// struct __MacroEvaluationContext\(macro.genericSignature) {
|
||||
/// typealias SignatureType = \(macro.signature)
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// So that we can use all of Swift's native name lookup and type resolution
|
||||
/// facilities to map the parsed signature type back into a semantic \c Type
|
||||
/// AST and a set of requiremnets.
|
||||
class MacroContextRequest
|
||||
: public SimpleRequest<MacroContextRequest,
|
||||
StructDecl *(std::string, ModuleDecl *),
|
||||
/// Lookup all macros with the given name that are visible from the given
|
||||
/// module.
|
||||
class MacroLookupRequest
|
||||
: public SimpleRequest<MacroLookupRequest,
|
||||
ArrayRef<Macro *>(Identifier, ModuleDecl *),
|
||||
RequestFlags::Cached> {
|
||||
public:
|
||||
using SimpleRequest::SimpleRequest;
|
||||
@@ -3760,8 +3746,8 @@ public:
|
||||
private:
|
||||
friend SimpleRequest;
|
||||
|
||||
StructDecl *evaluate(Evaluator &evaluator,
|
||||
std::string macroName, ModuleDecl *mod) const;
|
||||
ArrayRef<Macro *> evaluate(Evaluator &evaluator,
|
||||
Identifier macroName, ModuleDecl *mod) const;
|
||||
|
||||
public:
|
||||
bool isCached() const { return true; }
|
||||
@@ -3772,6 +3758,7 @@ void simple_display(llvm::raw_ostream &out, Type value);
|
||||
void simple_display(llvm::raw_ostream &out, const TypeRepr *TyR);
|
||||
void simple_display(llvm::raw_ostream &out, ImplicitMemberAction action);
|
||||
void simple_display(llvm::raw_ostream &out, ResultBuilderBodyPreCheck pck);
|
||||
void simple_display(llvm::raw_ostream &out, const Macro *macro);
|
||||
|
||||
#define SWIFT_TYPEID_ZONE TypeChecker
|
||||
#define SWIFT_TYPEID_HEADER "swift/AST/TypeCheckerTypeIDZone.def"
|
||||
|
||||
@@ -440,6 +440,6 @@ SWIFT_REQUEST(TypeChecker, GetTypeWrapperInitializer,
|
||||
SWIFT_REQUEST(TypeChecker, SynthesizeHasSymbolQueryRequest,
|
||||
FuncDecl *(ValueDecl *),
|
||||
Cached, NoLocationInfo)
|
||||
SWIFT_REQUEST(TypeChecker, MacroContextRequest,
|
||||
StructDecl *(std::string, ModuleDecl *),
|
||||
SWIFT_REQUEST(TypeChecker, MacroLookupRequest,
|
||||
ArrayRef<Macro *>(Identifier, ModuleDecl *),
|
||||
Cached, NoLocationInfo)
|
||||
|
||||
@@ -1104,6 +1104,9 @@ def enable_stack_protector :
|
||||
def disable_stack_protector :
|
||||
Flag<["-"], "disable-stack-protector">,
|
||||
HelpText<"Disable the stack-protector">;
|
||||
def enable_move_inout_stack_protector :
|
||||
Flag<["-"], "enable-move-inout-stack-protector">,
|
||||
HelpText<"Enable the stack protector by moving values to temporaries">;
|
||||
|
||||
def enable_new_llvm_pass_manager :
|
||||
Flag<["-"], "enable-new-llvm-pass-manager">,
|
||||
|
||||
@@ -184,6 +184,7 @@ OptionalBridgedFunction
|
||||
PassContext_loadFunction(BridgedPassContext context, llvm::StringRef name);
|
||||
|
||||
SwiftInt SILOptions_enableStackProtection(BridgedPassContext context);
|
||||
SwiftInt SILOptions_enableMoveInoutStackProtection(BridgedPassContext context);
|
||||
|
||||
SWIFT_END_NULLABILITY_ANNOTATIONS
|
||||
|
||||
|
||||
@@ -4911,7 +4911,7 @@ public:
|
||||
///
|
||||
/// \returns The opened type of the macro with this name, or the null \c Type
|
||||
/// if no such macro exists.
|
||||
Type getTypeOfMacroReference(StringRef macro, Expr *anchor);
|
||||
Type getTypeOfMacroReference(Identifier macroName, Expr *anchor);
|
||||
#endif
|
||||
|
||||
/// Retrieve a list of generic parameter types solver has "opened" (replaced
|
||||
|
||||
@@ -319,3 +319,27 @@ StringRef CompilerPlugin::invokeTypeSignature() const {
|
||||
llvm_unreachable("Incompatible host compiler");
|
||||
#endif
|
||||
}
|
||||
|
||||
StringRef CompilerPlugin::invokeOwningModule() const {
|
||||
#if __clang__
|
||||
using Method = SWIFT_CC CharBuffer(
|
||||
SWIFT_CONTEXT const void *, const void *, const void *);
|
||||
auto method = getWitnessMethodUnsafe<Method>(
|
||||
WitnessTableEntry::OwningModule);
|
||||
return method(metadata, metadata, witnessTable).str();
|
||||
#else
|
||||
llvm_unreachable("Incompatible host compiler");
|
||||
#endif
|
||||
}
|
||||
|
||||
StringRef CompilerPlugin::invokeSupplementalSignatureModules() const {
|
||||
#if __clang__
|
||||
using Method = SWIFT_CC CharBuffer(
|
||||
SWIFT_CONTEXT const void *, const void *, const void *);
|
||||
auto method = getWitnessMethodUnsafe<Method>(
|
||||
WitnessTableEntry::SupplementalSignatureModules);
|
||||
return method(metadata, metadata, witnessTable).str();
|
||||
#else
|
||||
llvm_unreachable("Incompatible host compiler");
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import SwiftParser
|
||||
import SwiftSyntax
|
||||
@_spi(Testing) import _SwiftSyntaxMacros
|
||||
|
||||
@@ -81,43 +82,107 @@ private func allocateUTF8String(
|
||||
}
|
||||
}
|
||||
|
||||
@_cdecl("swift_ASTGen_getMacroGenericSignature")
|
||||
public func getMacroGenericSignature(
|
||||
macroPtr: UnsafeMutablePointer<UInt8>,
|
||||
genericSignaturePtr: UnsafeMutablePointer<UnsafePointer<UInt8>?>,
|
||||
genericSignatureLengthPtr: UnsafeMutablePointer<Int>
|
||||
) {
|
||||
macroPtr.withMemoryRebound(to: ExportedMacro.self, capacity: 1) { macro in
|
||||
guard let genericSig = macro.pointee.macro.genericSignature else {
|
||||
(genericSignaturePtr.pointee, genericSignatureLengthPtr.pointee) = (nil, 0)
|
||||
return
|
||||
}
|
||||
|
||||
(genericSignaturePtr.pointee, genericSignatureLengthPtr.pointee) =
|
||||
allocateUTF8String(genericSig.description)
|
||||
}
|
||||
}
|
||||
|
||||
/// Query the type signature of the given macro.
|
||||
@_cdecl("swift_ASTGen_getMacroTypeSignature")
|
||||
public func getMacroTypeSignature(
|
||||
macroPtr: UnsafeMutablePointer<UInt8>,
|
||||
evaluationContextPtr: UnsafeMutablePointer<UnsafePointer<UInt8>?>,
|
||||
evaluationContextLengthPtr: UnsafeMutablePointer<Int>
|
||||
signaturePtr: UnsafeMutablePointer<UnsafePointer<UInt8>?>,
|
||||
signatureLengthPtr: UnsafeMutablePointer<Int>
|
||||
) {
|
||||
macroPtr.withMemoryRebound(to: ExportedMacro.self, capacity: 1) { macro in
|
||||
(evaluationContextPtr.pointee, evaluationContextLengthPtr.pointee) =
|
||||
allocateUTF8String(macro.pointee.evaluationContext, nullTerminated: true)
|
||||
(signaturePtr.pointee, signatureLengthPtr.pointee) =
|
||||
allocateUTF8String(macro.pointee.macro.signature.description)
|
||||
}
|
||||
}
|
||||
|
||||
extension ExportedMacro {
|
||||
var evaluationContext: String {
|
||||
"""
|
||||
struct __MacroEvaluationContext\(self.macro.genericSignature?.description ?? "") {
|
||||
typealias SignatureType = \(self.macro.signature)
|
||||
}
|
||||
"""
|
||||
/// Query the documentation of the given macro.
|
||||
@_cdecl("swift_ASTGen_getMacroDocumentation")
|
||||
public func getMacroDocumentation(
|
||||
macroPtr: UnsafeMutablePointer<UInt8>,
|
||||
documentationPtr: UnsafeMutablePointer<UnsafePointer<UInt8>?>,
|
||||
documentationLengthPtr: UnsafeMutablePointer<Int>
|
||||
) {
|
||||
macroPtr.withMemoryRebound(to: ExportedMacro.self, capacity: 1) { macro in
|
||||
(documentationPtr.pointee, documentationLengthPtr.pointee) =
|
||||
allocateUTF8String(macro.pointee.macro.documentation)
|
||||
}
|
||||
}
|
||||
|
||||
/// Query the macro evaluation context of the given macro.
|
||||
/// Query the owning module of the given macro.
|
||||
@_cdecl("swift_ASTGen_getMacroOwningModule")
|
||||
public func getMacroOwningModule(
|
||||
macroPtr: UnsafeMutablePointer<UInt8>,
|
||||
owningModulePtr: UnsafeMutablePointer<UnsafePointer<UInt8>?>,
|
||||
owningModuleLengthPtr: UnsafeMutablePointer<Int>
|
||||
) {
|
||||
macroPtr.withMemoryRebound(to: ExportedMacro.self, capacity: 1) { macro in
|
||||
(owningModulePtr.pointee, owningModuleLengthPtr.pointee) =
|
||||
allocateUTF8String(macro.pointee.macro.owningModule)
|
||||
}
|
||||
}
|
||||
|
||||
/// Query the supplemental signature modules of the given macro,
|
||||
/// as a semicolon-separated string
|
||||
@_cdecl("swift_ASTGen_getMacroSupplementalSignatureModules")
|
||||
public func getMacroSupplementableSignatureModules(
|
||||
macroPtr: UnsafeMutablePointer<UInt8>,
|
||||
modulesPtr: UnsafeMutablePointer<UnsafePointer<UInt8>?>,
|
||||
modulesLengthPtr: UnsafeMutablePointer<Int>
|
||||
) {
|
||||
macroPtr.withMemoryRebound(to: ExportedMacro.self, capacity: 1) { macro in
|
||||
let modules = macro.pointee.macro.supplementalSignatureModules
|
||||
.joined(separator: ";")
|
||||
(modulesPtr.pointee, modulesLengthPtr.pointee) =
|
||||
allocateUTF8String(modules)
|
||||
}
|
||||
}
|
||||
|
||||
/// Query the macro evaluation context given the evaluation
|
||||
/// context sources.
|
||||
@_cdecl("swift_ASTGen_getMacroEvaluationContext")
|
||||
public func getMacroEvaluationContext(
|
||||
sourceFilePtr: UnsafePointer<UInt8>,
|
||||
declContext: UnsafeMutableRawPointer,
|
||||
context: UnsafeMutableRawPointer,
|
||||
macroPtr: UnsafeMutablePointer<UInt8>,
|
||||
contextPtr: UnsafeMutablePointer<UnsafeMutableRawPointer?>
|
||||
) {
|
||||
contextPtr.pointee = macroPtr.withMemoryRebound(to: ExportedMacro.self, capacity: 1) { macro in
|
||||
return ASTGenVisitor(ctx: context, base: sourceFilePtr, declContext: declContext)
|
||||
.visit(StructDeclSyntax(stringLiteral: macro.pointee.evaluationContext))
|
||||
.rawValue
|
||||
evaluatedSourceBuffer: UnsafePointer<UInt8>,
|
||||
evaluatedSourceBufferLength: Int
|
||||
) -> UnsafeMutableRawPointer? {
|
||||
let evaluatedSource = UnsafeBufferPointer(
|
||||
start: evaluatedSourceBuffer,
|
||||
count: evaluatedSourceBufferLength
|
||||
)
|
||||
let sourceFile = Parser.parse(source: evaluatedSource)
|
||||
|
||||
// Dig out the top-level typealias declaration. That's all we'll
|
||||
// parse.
|
||||
guard let typealiasDecl = sourceFile.statements.first(
|
||||
where: { item in item.item.is(TypealiasDeclSyntax.self)
|
||||
})?.item.as(TypealiasDeclSyntax.self) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Parse and ASTGen that top-level declaration.
|
||||
// FIXME: we need to emit diagnostics from this.
|
||||
return ASTGenVisitor(
|
||||
ctx: context, base: sourceFilePtr, declContext: declContext
|
||||
).visit(typealiasDecl).rawValue
|
||||
}
|
||||
|
||||
@_cdecl("swift_ASTGen_evaluateMacro")
|
||||
|
||||
@@ -69,4 +69,20 @@ public protocol _CompilerPlugin {
|
||||
/// - Returns: A newly allocated buffer containing the type signature. The
|
||||
/// caller is responsible for managing the memory.
|
||||
static func _typeSignature() -> (UnsafePointer<UInt8>, count: Int)
|
||||
|
||||
|
||||
/// Returns the module that owns this macro.
|
||||
///
|
||||
/// - Returns: A newly allocated buffer containing the owning module name. The
|
||||
/// caller is responsible for managing the memory.
|
||||
static func _owningModule() -> (UnsafePointer<UInt8>, count: Int)
|
||||
|
||||
/// Returns the set of modules that are needed (beyond the owning module) to
|
||||
/// process the module signature.
|
||||
///
|
||||
/// - Returns: A newly allocated buffer containing a string with all of the
|
||||
/// supplemental signature module names, separated by semicolons. The caller
|
||||
/// is responsible for managing the memory.
|
||||
static func _supplementalSignatureModules()
|
||||
-> (UnsafePointer<UInt8>, count: Int)
|
||||
}
|
||||
|
||||
@@ -1825,6 +1825,9 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args,
|
||||
Opts.EnableStackProtection =
|
||||
Args.hasFlag(OPT_enable_stack_protector, OPT_disable_stack_protector,
|
||||
Opts.EnableStackProtection);
|
||||
Opts.EnableMoveInoutStackProtection =
|
||||
Args.hasFlag(OPT_enable_move_inout_stack_protector, OPT_disable_stack_protector,
|
||||
Opts.EnableMoveInoutStackProtection);
|
||||
Opts.VerifyAll |= Args.hasArg(OPT_sil_verify_all);
|
||||
Opts.VerifyNone |= Args.hasArg(OPT_sil_verify_none);
|
||||
Opts.DebugSerialization |= Args.hasArg(OPT_sil_debug_serialization);
|
||||
|
||||
@@ -1638,3 +1638,8 @@ SwiftInt SILOptions_enableStackProtection(BridgedPassContext context) {
|
||||
SILModule *mod = castToPassInvocation(context)->getPassManager()->getModule();
|
||||
return mod->getOptions().EnableStackProtection;
|
||||
}
|
||||
|
||||
SwiftInt SILOptions_enableMoveInoutStackProtection(BridgedPassContext context) {
|
||||
SILModule *mod = castToPassInvocation(context)->getPassManager()->getModule();
|
||||
return mod->getOptions().EnableMoveInoutStackProtection;
|
||||
}
|
||||
|
||||
@@ -1200,7 +1200,8 @@ namespace {
|
||||
if (!protocol)
|
||||
return Type();
|
||||
|
||||
auto openedType = CS.getTypeOfMacroReference(kind, expr);
|
||||
auto openedType = CS.getTypeOfMacroReference(
|
||||
ctx.getIdentifier(kind), expr);
|
||||
if (!openedType)
|
||||
return Type();
|
||||
|
||||
@@ -3633,7 +3634,7 @@ namespace {
|
||||
auto &ctx = CS.getASTContext();
|
||||
if (ctx.LangOpts.hasFeature(Feature::Macros)) {
|
||||
auto macroIdent = expr->getMacroName().getBaseIdentifier();
|
||||
auto refType = CS.getTypeOfMacroReference(macroIdent.str(), expr);
|
||||
auto refType = CS.getTypeOfMacroReference(macroIdent, expr);
|
||||
if (!refType) {
|
||||
ctx.Diags.diagnose(expr->getMacroNameLoc(), diag::macro_undefined,
|
||||
macroIdent)
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "TypeChecker.h"
|
||||
#include "swift/AST/GenericEnvironment.h"
|
||||
#include "swift/AST/Initializer.h"
|
||||
#include "swift/AST/Macro.h"
|
||||
#include "swift/AST/ParameterList.h"
|
||||
#include "swift/AST/ProtocolConformance.h"
|
||||
#include "swift/AST/TypeCheckRequests.h"
|
||||
@@ -2472,25 +2473,22 @@ ConstraintSystem::getTypeOfMemberReference(
|
||||
}
|
||||
|
||||
#if SWIFT_SWIFT_PARSER
|
||||
Type ConstraintSystem::getTypeOfMacroReference(StringRef macroName,
|
||||
Type ConstraintSystem::getTypeOfMacroReference(Identifier macroName,
|
||||
Expr *anchor) {
|
||||
auto req = MacroContextRequest{macroName.str(), DC->getParentModule()};
|
||||
auto *macroCtx = evaluateOrDefault(getASTContext().evaluator, req, nullptr);
|
||||
if (!macroCtx)
|
||||
auto req = MacroLookupRequest{macroName, DC->getParentModule()};
|
||||
auto macros = evaluateOrDefault(getASTContext().evaluator, req, { });
|
||||
if (macros.empty())
|
||||
return Type();
|
||||
|
||||
auto *locator = getConstraintLocator(anchor);
|
||||
// Dig through to __MacroEvaluationContext.SignatureType
|
||||
auto sig = getASTContext().getIdentifier("SignatureType");
|
||||
auto *signature = cast<TypeAliasDecl>(macroCtx->lookupDirect(sig).front());
|
||||
auto type = signature->getUnderlyingType();
|
||||
// FIXME: Handle macro overloading.
|
||||
auto macro = macros.front();
|
||||
|
||||
// Open any the generic types.
|
||||
OpenedTypeMap replacements;
|
||||
openGeneric(signature->getParent(), signature->getGenericSignature(),
|
||||
locator, replacements);
|
||||
openGeneric(macro->owningModule, macro->genericSignature,
|
||||
getConstraintLocator(anchor), replacements);
|
||||
|
||||
return openType(type, replacements);
|
||||
return openType(macro->signature, replacements);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -19,8 +19,10 @@
|
||||
#include "swift/AST/ASTContext.h"
|
||||
#include "swift/AST/CompilerPlugin.h"
|
||||
#include "swift/AST/Expr.h"
|
||||
#include "swift/AST/Macro.h"
|
||||
#include "swift/AST/SourceFile.h"
|
||||
#include "swift/AST/TypeCheckRequests.h"
|
||||
#include "swift/Basic/Defer.h"
|
||||
#include "swift/Basic/SourceManager.h"
|
||||
#include "swift/Basic/StringExtras.h"
|
||||
#include "swift/Parse/Lexer.h"
|
||||
@@ -32,54 +34,79 @@ extern "C" void *swift_ASTGen_lookupMacro(const char *macroName);
|
||||
|
||||
extern "C" void swift_ASTGen_destroyMacro(void *macro);
|
||||
|
||||
extern "C" void
|
||||
extern "C" void *
|
||||
swift_ASTGen_getMacroEvaluationContext(const void *sourceFile,
|
||||
void *declContext, void *astContext,
|
||||
void *macro, void **evaluationContext);
|
||||
const char *evaluatedSource,
|
||||
ptrdiff_t evaluatedSourceLength);
|
||||
|
||||
extern "C" ptrdiff_t swift_ASTGen_evaluateMacro(
|
||||
void *sourceFile, const void *sourceLocation,
|
||||
const char **evaluatedSource, ptrdiff_t *evaluatedSourceLength);
|
||||
|
||||
extern "C" void
|
||||
swift_ASTGen_getMacroTypeSignature(void *macro,
|
||||
const char **evaluationContextPtr,
|
||||
ptrdiff_t *evaluationContextLengthPtr);
|
||||
swift_ASTGen_getMacroGenericSignature(void *macro,
|
||||
const char **genericSignaturePtr,
|
||||
ptrdiff_t *genericSignatureLengthPtr);
|
||||
|
||||
extern "C" void
|
||||
swift_ASTGen_getMacroTypeSignature(void *macro,
|
||||
const char **signaturePtr,
|
||||
ptrdiff_t *signatureLengthPtr);
|
||||
|
||||
extern "C" void
|
||||
swift_ASTGen_getMacroOwningModule(void *macro,
|
||||
const char **owningModuleNamePtr,
|
||||
ptrdiff_t *owningModuleNameLengthPtr);
|
||||
|
||||
extern "C" void
|
||||
swift_ASTGen_getMacroSupplementalSignatureModules(
|
||||
void *macro, const char **moduleNamesPtr, ptrdiff_t *moduleNamesLengthPtr);
|
||||
|
||||
/// Create a new macro signature context buffer describing the macro signature.
|
||||
///
|
||||
/// The macro signature is a user-defined generic signature and return
|
||||
/// type that serves as the "interface type" of references to the macro. The
|
||||
/// current implementation takes those pieces of syntax from the macro itself,
|
||||
/// then inserts them into a Swift typealias that looks like
|
||||
///
|
||||
/// \code
|
||||
/// typealias __MacroEvaluationContext\(macro.genericSignature ?? "") =
|
||||
/// \(macro.signature)
|
||||
/// \endcode
|
||||
///
|
||||
/// So that we can use all of Swift's native name lookup and type resolution
|
||||
/// facilities to map the parsed signature type back into a semantic
|
||||
/// \c GenericSignature and \c Type ASTs. The macro signature source above is
|
||||
/// provided via \c signatureSource.
|
||||
static NullTerminatedStringRef
|
||||
getPluginMacroTypeSignature(CompilerPlugin *plugin, ASTContext &ctx) {
|
||||
auto genSig = plugin->invokeGenericSignature();
|
||||
auto typeSig = plugin->invokeTypeSignature();
|
||||
getMacroSignatureContextBuffer(
|
||||
ASTContext &ctx, Optional<StringRef> genericSignature,
|
||||
StringRef typeSignature
|
||||
) {
|
||||
std::string source;
|
||||
llvm::raw_string_ostream out(source);
|
||||
out << "struct __MacroEvaluationContext" << (genSig ? *genSig : "") << " {\n"
|
||||
<< " typealias SignatureType = " << typeSig << "\n"
|
||||
<< "}";
|
||||
out << "typealias __MacroEvaluationContext"
|
||||
<< (genericSignature ? *genericSignature : "")
|
||||
<< " = " << typeSignature << "\n";
|
||||
auto len = source.length();
|
||||
auto *buffer = (char *)malloc(len + 1);
|
||||
memcpy(buffer, source.data(), len + 1);
|
||||
return {buffer, len};
|
||||
}
|
||||
|
||||
StructDecl *MacroContextRequest::evaluate(Evaluator &evaluator,
|
||||
std::string macroName,
|
||||
ModuleDecl *mod) const {
|
||||
#if SWIFT_SWIFT_PARSER
|
||||
auto &ctx = mod->getASTContext();
|
||||
auto *builtinMacro = swift_ASTGen_lookupMacro(macroName.c_str());
|
||||
NullTerminatedStringRef evaluatedSource;
|
||||
if (builtinMacro) {
|
||||
const char *evaluatedSourcePtr;
|
||||
ptrdiff_t evaluatedSourceLength;
|
||||
swift_ASTGen_getMacroTypeSignature(builtinMacro, &evaluatedSourcePtr,
|
||||
&evaluatedSourceLength);
|
||||
evaluatedSource = NullTerminatedStringRef(
|
||||
evaluatedSourcePtr, (size_t)evaluatedSourceLength);
|
||||
} else if (auto *plugin = ctx.getLoadedPlugin(macroName)) {
|
||||
evaluatedSource = getPluginMacroTypeSignature(plugin, ctx);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
/// Compute the macro signature for a macro given the source code for its
|
||||
/// generic signature and type signature.
|
||||
static Optional<std::pair<GenericSignature, Type>>
|
||||
getMacroSignature(
|
||||
ModuleDecl *mod, Identifier macroName,
|
||||
Optional<StringRef> genericSignature,
|
||||
StringRef typeSignature
|
||||
) {
|
||||
// Form a buffer containing the macro signature context.
|
||||
ASTContext &ctx = mod->getASTContext();
|
||||
StringRef signatureSource = getMacroSignatureContextBuffer(
|
||||
ctx, genericSignature, typeSignature);
|
||||
|
||||
// Create a new source buffer with the contents of the macro's
|
||||
// signature.
|
||||
@@ -90,39 +117,211 @@ StructDecl *MacroContextRequest::evaluate(Evaluator &evaluator,
|
||||
out << "Macro signature of #" << macroName;
|
||||
}
|
||||
auto macroBuffer = llvm::MemoryBuffer::getMemBuffer(
|
||||
evaluatedSource, bufferName);
|
||||
signatureSource, bufferName);
|
||||
|
||||
// FIXME: We should tell the source manager that this is a macro signature
|
||||
// buffer.
|
||||
unsigned macroBufferID =
|
||||
sourceMgr.addNewSourceBuffer(std::move(macroBuffer));
|
||||
auto macroSourceFile = new (ctx) SourceFile(
|
||||
*mod, SourceFileKind::Library, macroBufferID);
|
||||
mod->addAuxiliaryFile(*macroSourceFile);
|
||||
|
||||
// Make sure implicit imports are resolved in this file.
|
||||
performImportResolution(*macroSourceFile);
|
||||
// FIXME: Inject imports, which we don't yet have everywhere.
|
||||
|
||||
// Parse the struct declaration used for the macro evaluation context.
|
||||
auto *start = sourceMgr.getLocForBufferStart(macroBufferID)
|
||||
.getOpaquePointerValue();
|
||||
if (builtinMacro) {
|
||||
void *context = nullptr;
|
||||
swift_ASTGen_getMacroEvaluationContext(
|
||||
(const void *)start, (void *)(DeclContext *)macroSourceFile,
|
||||
(void *)&ctx, builtinMacro, &context);
|
||||
ctx.addCleanup([builtinMacro]() {
|
||||
swift_ASTGen_destroyMacro(builtinMacro);
|
||||
});
|
||||
return dyn_cast<StructDecl>((Decl *)context);
|
||||
} else {
|
||||
Parser parser(macroBufferID, *macroSourceFile, &ctx.Diags, nullptr,
|
||||
nullptr);
|
||||
parser.consumeTokenWithoutFeedingReceiver();
|
||||
DeclAttributes attrs;
|
||||
auto parsedResult = parser.parseDeclStruct(Parser::PD_Default, attrs);
|
||||
if (parsedResult.isParseError() || parsedResult.isNull())
|
||||
return nullptr; // TODO: Diagnose this properly.
|
||||
return parsedResult.get();
|
||||
}
|
||||
#else
|
||||
auto decl = (Decl *)swift_ASTGen_getMacroEvaluationContext(
|
||||
start, (DeclContext *)macroSourceFile,
|
||||
&ctx, signatureSource.data(), signatureSource.size());
|
||||
|
||||
if (!decl)
|
||||
return None;
|
||||
|
||||
// Make sure imports are resolved in this file.
|
||||
performImportResolution(*macroSourceFile);
|
||||
|
||||
auto typealias = cast<TypeAliasDecl>(decl);
|
||||
return std::make_pair(
|
||||
typealias->getGenericSignature(), typealias->getUnderlyingType());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Create a macro.
|
||||
static Macro *createMacro(
|
||||
ModuleDecl *mod, Identifier macroName,
|
||||
Macro::ImplementationKind implKind,
|
||||
Optional<StringRef> genericSignature, StringRef typeSignature,
|
||||
StringRef owningModuleName,
|
||||
ArrayRef<StringRef> supplementalImportModuleNames,
|
||||
void* opaqueHandle
|
||||
) {
|
||||
ASTContext &ctx = mod->getASTContext();
|
||||
|
||||
// Look up the owning module.
|
||||
ModuleDecl *owningModule = ctx.getLoadedModule(
|
||||
ctx.getIdentifier(owningModuleName));
|
||||
if (!owningModule) {
|
||||
// FIXME: diagnostic here
|
||||
return nullptr;
|
||||
}
|
||||
// FIXME: Check that mod imports owningModule
|
||||
|
||||
// Look up all of the supplemental import modules.
|
||||
SmallVector<ModuleDecl *, 1> supplementalImportModules;
|
||||
for (auto supplementalModuleName : supplementalImportModuleNames) {
|
||||
auto supplementalModuleId = ctx.getIdentifier(supplementalModuleName);
|
||||
if (auto supplementalModule = ctx.getLoadedModule(supplementalModuleId)) {
|
||||
supplementalImportModules.push_back(supplementalModule);
|
||||
|
||||
// FIXME: Check that mod imports supplementalModule somewhere.
|
||||
}
|
||||
}
|
||||
|
||||
// Get the type signature of the macro.
|
||||
auto signature = getMacroSignature(
|
||||
mod, macroName, genericSignature, typeSignature);
|
||||
if (!signature) {
|
||||
// FIXME: Swap in ErrorTypes, perhaps?
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// FIXME: All macros are expression macros right now
|
||||
return new (ctx) Macro(
|
||||
Macro::Expression, implKind, macroName,
|
||||
signature->first, signature->second,
|
||||
owningModule, supplementalImportModules,
|
||||
opaqueHandle);
|
||||
}
|
||||
|
||||
/// Create a builtin macro.
|
||||
static Macro *createBuiltinMacro(
|
||||
ModuleDecl *mod, Identifier macroName, void *opaqueHandle) {
|
||||
// Get the macro generic signature.
|
||||
const char *genericSignaturePtr;
|
||||
ptrdiff_t genericSignatureLength;
|
||||
swift_ASTGen_getMacroGenericSignature(opaqueHandle, &genericSignaturePtr,
|
||||
&genericSignatureLength);
|
||||
SWIFT_DEFER {
|
||||
free((void*)genericSignaturePtr);
|
||||
};
|
||||
|
||||
Optional<StringRef> genericSignature;
|
||||
if (genericSignaturePtr && genericSignatureLength)
|
||||
genericSignature = StringRef(genericSignaturePtr, genericSignatureLength);
|
||||
|
||||
// Get the macro type signature.
|
||||
const char *typeSignaturePtr;
|
||||
ptrdiff_t typeSignatureLength;
|
||||
swift_ASTGen_getMacroTypeSignature(opaqueHandle, &typeSignaturePtr,
|
||||
&typeSignatureLength);
|
||||
SWIFT_DEFER {
|
||||
free((void*)typeSignaturePtr);
|
||||
};
|
||||
StringRef typeSignature = StringRef(typeSignaturePtr, typeSignatureLength);
|
||||
|
||||
// Get the owning module name.
|
||||
const char *owningModuleNamePtr;
|
||||
ptrdiff_t owningModuleNameLength;
|
||||
swift_ASTGen_getMacroOwningModule(opaqueHandle, &owningModuleNamePtr,
|
||||
&owningModuleNameLength);
|
||||
SWIFT_DEFER {
|
||||
free((void*)owningModuleNamePtr);
|
||||
};
|
||||
StringRef owningModuleName = StringRef(
|
||||
owningModuleNamePtr, owningModuleNameLength);
|
||||
|
||||
// Get the supplemental signature module names.
|
||||
const char *supplementalModuleNamesPtr;
|
||||
ptrdiff_t supplementalModuleNamesLength;
|
||||
swift_ASTGen_getMacroSupplementalSignatureModules(
|
||||
opaqueHandle, &supplementalModuleNamesPtr,
|
||||
&supplementalModuleNamesLength);
|
||||
SWIFT_DEFER {
|
||||
free((void*)supplementalModuleNamesPtr);
|
||||
};
|
||||
SmallVector<StringRef, 2> supplementalModuleNames;
|
||||
StringRef(owningModuleNamePtr, owningModuleNameLength)
|
||||
.split(supplementalModuleNames, ";", -1, false);
|
||||
|
||||
return createMacro(
|
||||
mod, macroName, Macro::ImplementationKind::Builtin,
|
||||
genericSignature, typeSignature,
|
||||
owningModuleName, supplementalModuleNames,
|
||||
opaqueHandle);
|
||||
}
|
||||
|
||||
/// Create a plugin-based macro.
|
||||
static Macro *createPluginMacro(
|
||||
ModuleDecl *mod, Identifier macroName, CompilerPlugin *plugin) {
|
||||
auto genSignature = plugin->invokeGenericSignature();
|
||||
SWIFT_DEFER {
|
||||
if (genSignature)
|
||||
free((void*)genSignature->data());
|
||||
};
|
||||
|
||||
auto typeSignature = plugin->invokeTypeSignature();
|
||||
SWIFT_DEFER {
|
||||
free((void*)typeSignature.data());
|
||||
};
|
||||
|
||||
auto owningModuleName = plugin->invokeOwningModule();
|
||||
SWIFT_DEFER {
|
||||
free((void*)owningModuleName.data());
|
||||
};
|
||||
|
||||
// Get the supplemental signature module names.
|
||||
auto supplementalModuleNamesStr =
|
||||
plugin->invokeSupplementalSignatureModules();
|
||||
SWIFT_DEFER {
|
||||
free((void*)supplementalModuleNamesStr.data());
|
||||
};
|
||||
SmallVector<StringRef, 2> supplementalModuleNames;
|
||||
supplementalModuleNamesStr
|
||||
.split(supplementalModuleNames, ";", -1, false);
|
||||
|
||||
return createMacro(
|
||||
mod, macroName, Macro::ImplementationKind::Plugin, genSignature,
|
||||
typeSignature, owningModuleName, supplementalModuleNames, plugin);
|
||||
}
|
||||
|
||||
ArrayRef<Macro *> MacroLookupRequest::evaluate(
|
||||
Evaluator &evaluator, Identifier macroName, ModuleDecl *mod
|
||||
) const {
|
||||
#if SWIFT_SWIFT_PARSER
|
||||
ASTContext &ctx = mod->getASTContext();
|
||||
SmallVector<Macro *, 2> macros;
|
||||
|
||||
// Look for a builtin macro with this name.
|
||||
if (auto *builtinHandle = swift_ASTGen_lookupMacro(
|
||||
macroName.str().str().c_str())) {
|
||||
if (auto builtinMacro = createBuiltinMacro(mod, macroName, builtinHandle)) {
|
||||
macros.push_back(builtinMacro);
|
||||
|
||||
// Make sure we clean up after the macro.
|
||||
ctx.addCleanup([builtinHandle]() {
|
||||
swift_ASTGen_destroyMacro(builtinHandle);
|
||||
});
|
||||
} else {
|
||||
// Destroy the builtin macro handle now; nothing references it.
|
||||
swift_ASTGen_destroyMacro(builtinHandle);
|
||||
}
|
||||
}
|
||||
|
||||
// Look for a loaded plugin based on the macro name.
|
||||
// FIXME: This API needs to be able to return multiple plugins, because
|
||||
// several plugins could export a macro with the same name.
|
||||
if (auto *plugin = ctx.getLoadedPlugin(macroName.str())) {
|
||||
if (auto pluginMacro = createPluginMacro(mod, macroName, plugin)) {
|
||||
macros.push_back(pluginMacro);
|
||||
}
|
||||
}
|
||||
|
||||
return ctx.AllocateCopy(macros);
|
||||
#else
|
||||
return { };
|
||||
#endif // SWIFT_SWIFT_PARSER
|
||||
}
|
||||
|
||||
@@ -145,6 +344,9 @@ Expr *swift::expandMacroExpr(
|
||||
// Evaluate the macro.
|
||||
NullTerminatedStringRef evaluatedSource;
|
||||
|
||||
// FIXME: The caller should tell us what macro is being expanded, so we
|
||||
// don't do this lookup again.
|
||||
|
||||
// Built-in macros go through `MacroSystem` in Swift Syntax linked to this
|
||||
// compiler.
|
||||
if (auto *macro = swift_ASTGen_lookupMacro(macroName.str().c_str())) {
|
||||
|
||||
@@ -28,6 +28,24 @@ struct StringifyMacro: _CompilerPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -29,6 +29,24 @@ struct DummyMacro: _CompilerPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// RUN: %target-sil-opt -wmo -stack-protection -enable-sil-verify-all %s | %FileCheck %s --check-prefix=CHECK --check-prefix=MODULE
|
||||
// RUN: %target-sil-opt -function-stack-protection -enable-sil-verify-all %s | %FileCheck %s --check-prefix=CHECK --check-prefix=FUNCTION
|
||||
// RUN: %target-sil-opt -wmo -stack-protection -enable-move-inout-stack-protector -enable-sil-verify-all %s | %FileCheck %s --check-prefix=CHECK --check-prefix=MOVE
|
||||
|
||||
// REQUIRES: swift_in_compiler
|
||||
|
||||
@@ -57,8 +58,7 @@ bb0:
|
||||
return %r : $()
|
||||
}
|
||||
// CHECK-LABEL: sil [stack_protection] @function_local_stack_obj
|
||||
// MODULE-NOT: copy_addr
|
||||
// FUNCTION: copy_addr
|
||||
// CHECK-NOT: copy_addr
|
||||
// CHECK: } // end sil function 'function_local_stack_obj'
|
||||
sil @function_local_stack_obj : $@convention(thin) () -> () {
|
||||
bb0:
|
||||
@@ -72,10 +72,8 @@ bb0:
|
||||
return %r : $()
|
||||
}
|
||||
|
||||
// MODULE-LABEL: sil @function_local_obj
|
||||
// FUNCTION-LABEL: sil [stack_protection] @function_local_obj
|
||||
// MODULE-NOT: copy_addr
|
||||
// FUNCTION: copy_addr
|
||||
// CHECK-LABEL: sil @function_local_obj
|
||||
// CHECK-NOT: copy_addr
|
||||
// CHECK: } // end sil function 'function_local_obj'
|
||||
sil @function_local_obj : $@convention(thin) () -> () {
|
||||
bb0:
|
||||
@@ -89,12 +87,16 @@ bb0:
|
||||
return %r : $()
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil [stack_protection] @inout_with_unknown_callers1
|
||||
// CHECK: [[T:%[0-9]+]] = alloc_stack $Int64
|
||||
// CHECK: copy_addr [take] %0 to [init] [[T]] : $*Int64
|
||||
// CHECK: address_to_pointer [stack_protection] [[T]]
|
||||
// CHECK: copy_addr [take] [[T]] to [init] %0 : $*Int64
|
||||
// CHECK: dealloc_stack [[T]] : $*Int64
|
||||
// MOVE-LABEL: sil [stack_protection] @inout_with_unknown_callers1
|
||||
// MODULE-LABEL: sil @inout_with_unknown_callers1
|
||||
// MOVE: [[T:%[0-9]+]] = alloc_stack $Int64
|
||||
// MOVE: copy_addr [take] %0 to [init] [[T]] : $*Int64
|
||||
// MOVE: address_to_pointer [stack_protection] [[T]]
|
||||
// MOVE: copy_addr [take] [[T]] to [init] %0 : $*Int64
|
||||
// MOVE: dealloc_stack [[T]] : $*Int64
|
||||
// MODULE-NOT: alloc_stack
|
||||
// MODULE-NOT: copy_addr
|
||||
// CHECK-MODULE: address_to_pointer [stack_protection] %0
|
||||
// CHECK: } // end sil function 'inout_with_unknown_callers1'
|
||||
sil @inout_with_unknown_callers1 : $@convention(thin) (@inout Int64) -> () {
|
||||
bb0(%0 : $*Int64):
|
||||
@@ -114,13 +116,17 @@ bb0(%0 : $*Int64):
|
||||
return %r : $()
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil [stack_protection] @inout_with_modify_access
|
||||
// CHECK: [[A:%[0-9]+]] = begin_access [modify] [dynamic] %0 : $*Int64
|
||||
// CHECK: [[T:%[0-9]+]] = alloc_stack $Int64
|
||||
// CHECK: copy_addr [take] [[A]] to [init] [[T]] : $*Int64
|
||||
// CHECK: address_to_pointer [stack_protection] [[T]]
|
||||
// CHECK: copy_addr [take] [[T]] to [init] [[A]] : $*Int64
|
||||
// CHECK: dealloc_stack [[T]] : $*Int64
|
||||
// MOVE-LABEL: sil [stack_protection] @inout_with_modify_access
|
||||
// MODULE-LABEL: sil @inout_with_modify_access
|
||||
// MOVE: [[A:%[0-9]+]] = begin_access [modify] [dynamic] %0 : $*Int64
|
||||
// MOVE: [[T:%[0-9]+]] = alloc_stack $Int64
|
||||
// MOVE: copy_addr [take] [[A]] to [init] [[T]] : $*Int64
|
||||
// MOVE: address_to_pointer [stack_protection] [[T]]
|
||||
// MOVE: copy_addr [take] [[T]] to [init] [[A]] : $*Int64
|
||||
// MOVE: dealloc_stack [[T]] : $*Int64
|
||||
// MODULE-NOT: alloc_stack
|
||||
// MODULE-NOT: copy_addr
|
||||
// CHECK-MODULE: address_to_pointer [stack_protection] %0
|
||||
// CHECK: } // end sil function 'inout_with_modify_access'
|
||||
sil @inout_with_modify_access : $@convention(thin) (@inout Int64) -> () {
|
||||
bb0(%0 : $*Int64):
|
||||
@@ -145,15 +151,18 @@ bb0(%0 : $*Int64):
|
||||
return %r : $()
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil [stack_protection] @inout_with_unknown_callers2
|
||||
// CHECK: [[T:%[0-9]+]] = alloc_stack $S
|
||||
// CHECK: copy_addr [take] %0 to [init] [[T]] : $*S
|
||||
// CHECK: [[A:%[0-9]+]] = struct_element_addr [[T]] : $*S, #S.a
|
||||
// CHECK: address_to_pointer [stack_protection] [[A]]
|
||||
// CHECK: [[B:%[0-9]+]] = struct_element_addr [[T]] : $*S, #S.b
|
||||
// CHECK: address_to_pointer [stack_protection] [[B]]
|
||||
// CHECK: copy_addr [take] [[T]] to [init] %0 : $*S
|
||||
// CHECK: dealloc_stack [[T]] : $*S
|
||||
// MOVE-LABEL: sil [stack_protection] @inout_with_unknown_callers2
|
||||
// MODULE-LABEL: sil @inout_with_unknown_callers2
|
||||
// MOVE: [[T:%[0-9]+]] = alloc_stack $S
|
||||
// MOVE: copy_addr [take] %0 to [init] [[T]] : $*S
|
||||
// MOVE: [[A:%[0-9]+]] = struct_element_addr [[T]] : $*S, #S.a
|
||||
// MOVE: address_to_pointer [stack_protection] [[A]]
|
||||
// MOVE: [[B:%[0-9]+]] = struct_element_addr [[T]] : $*S, #S.b
|
||||
// MOVE: address_to_pointer [stack_protection] [[B]]
|
||||
// MOVE: copy_addr [take] [[T]] to [init] %0 : $*S
|
||||
// MOVE: dealloc_stack [[T]] : $*S
|
||||
// MODULE-NOT: alloc_stack
|
||||
// MODULE-NOT: copy_addr
|
||||
// CHECK: } // end sil function 'inout_with_unknown_callers2'
|
||||
sil @inout_with_unknown_callers2 : $@convention(thin) (@inout S) -> () {
|
||||
bb0(%0 : $*S):
|
||||
@@ -165,15 +174,18 @@ bb0(%0 : $*S):
|
||||
return %r : $()
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil [stack_protection] @object_with_unknown_callers1
|
||||
// CHECK: [[I:%[0-9]+]] = ref_element_addr %0 : $C, #C.i
|
||||
// CHECK: [[A:%[0-9]+]] = begin_access [modify] [static] [[I]] : $*Int64
|
||||
// CHECK: [[T:%[0-9]+]] = alloc_stack $Int64
|
||||
// CHECK: copy_addr [take] [[A]] to [init] [[T]] : $*Int64
|
||||
// CHECK: address_to_pointer [stack_protection] [[T]]
|
||||
// CHECK: copy_addr [take] [[T]] to [init] [[A]] : $*Int64
|
||||
// CHECK: dealloc_stack [[T]] : $*Int64
|
||||
// CHECK: end_access [[A]] : $*Int64
|
||||
// MOVE-LABEL: sil [stack_protection] @object_with_unknown_callers1
|
||||
// MODULE-LABEL: sil @object_with_unknown_callers1
|
||||
// MOVE: [[I:%[0-9]+]] = ref_element_addr %0 : $C, #C.i
|
||||
// MOVE: [[A:%[0-9]+]] = begin_access [modify] [static] [[I]] : $*Int64
|
||||
// MOVE: [[T:%[0-9]+]] = alloc_stack $Int64
|
||||
// MOVE: copy_addr [take] [[A]] to [init] [[T]] : $*Int64
|
||||
// MOVE: address_to_pointer [stack_protection] [[T]]
|
||||
// MOVE: copy_addr [take] [[T]] to [init] [[A]] : $*Int64
|
||||
// MOVE: dealloc_stack [[T]] : $*Int64
|
||||
// MOVE: end_access [[A]] : $*Int64
|
||||
// MODULE-NOT: alloc_stack
|
||||
// MODULE-NOT: copy_addr
|
||||
// CHECK: } // end sil function 'object_with_unknown_callers1'
|
||||
sil @object_with_unknown_callers1 : $@convention(thin) (@guaranteed C) -> () {
|
||||
bb0(%0 : $C):
|
||||
@@ -185,16 +197,19 @@ bb0(%0 : $C):
|
||||
return %r : $()
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil [stack_protection] @object_with_unknown_callers2
|
||||
// CHECK: [[I:%[0-9]+]] = ref_element_addr %0 : $C, #C.i
|
||||
// CHECK: [[A:%[0-9]+]] = begin_access [modify] [static] [[I]] : $*Int64
|
||||
// CHECK: [[T:%[0-9]+]] = alloc_stack $Int64
|
||||
// CHECK: copy_addr [take] [[A]] to [init] [[T]] : $*Int64
|
||||
// CHECK: address_to_pointer [stack_protection] [[T]]
|
||||
// CHECK: address_to_pointer [stack_protection] [[T]]
|
||||
// CHECK: copy_addr [take] [[T]] to [init] [[A]] : $*Int64
|
||||
// CHECK: dealloc_stack [[T]] : $*Int64
|
||||
// CHECK: end_access [[A]] : $*Int64
|
||||
// MOVE-LABEL: sil [stack_protection] @object_with_unknown_callers2
|
||||
// MODULE-LABEL: sil @object_with_unknown_callers2
|
||||
// MOVE: [[I:%[0-9]+]] = ref_element_addr %0 : $C, #C.i
|
||||
// MOVE: [[A:%[0-9]+]] = begin_access [modify] [static] [[I]] : $*Int64
|
||||
// MOVE: [[T:%[0-9]+]] = alloc_stack $Int64
|
||||
// MOVE: copy_addr [take] [[A]] to [init] [[T]] : $*Int64
|
||||
// MOVE: address_to_pointer [stack_protection] [[T]]
|
||||
// MOVE: address_to_pointer [stack_protection] [[T]]
|
||||
// MOVE: copy_addr [take] [[T]] to [init] [[A]] : $*Int64
|
||||
// MOVE: dealloc_stack [[T]] : $*Int64
|
||||
// MOVE: end_access [[A]] : $*Int64
|
||||
// MODULE-NOT: alloc_stack
|
||||
// MODULE-NOT: copy_addr
|
||||
// CHECK: } // end sil function 'object_with_unknown_callers2'
|
||||
sil @object_with_unknown_callers2 : $@convention(thin) (@guaranteed C) -> () {
|
||||
bb0(%0 : $C):
|
||||
@@ -207,23 +222,26 @@ bb0(%0 : $C):
|
||||
return %r : $()
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil [stack_protection] @object_with_unknown_callers3
|
||||
// CHECK: [[I:%[0-9]+]] = ref_element_addr %0 : $C, #C.i
|
||||
// CHECK: [[AI:%[0-9]+]] = begin_access [modify] [static] [[I]] : $*Int64
|
||||
// CHECK: [[TI:%[0-9]+]] = alloc_stack $Int64
|
||||
// CHECK: copy_addr [take] [[AI]] to [init] [[TI]] : $*Int64
|
||||
// CHECK: address_to_pointer [stack_protection] [[TI]]
|
||||
// CHECK: [[J:%[0-9]+]] = ref_element_addr %0 : $C, #C.j
|
||||
// CHECK: [[AJ:%[0-9]+]] = begin_access [modify] [static] [[J]] : $*Int64
|
||||
// CHECK: [[TJ:%[0-9]+]] = alloc_stack $Int64
|
||||
// CHECK: copy_addr [take] [[AJ]] to [init] [[TJ]] : $*Int64
|
||||
// CHECK: copy_addr [take] [[TI]] to [init] [[AI]] : $*Int64
|
||||
// CHECK: end_access [[AI]] : $*Int64
|
||||
// CHECK: address_to_pointer [stack_protection] [[TJ]]
|
||||
// CHECK: copy_addr [take] [[TJ]] to [init] [[AJ]] : $*Int64
|
||||
// CHECK: dealloc_stack [[TJ]] : $*Int64
|
||||
// CHECK: dealloc_stack [[TI]] : $*Int64
|
||||
// CHECK: end_access [[AJ]] : $*Int64
|
||||
// MOVE-LABEL: sil [stack_protection] @object_with_unknown_callers3
|
||||
// MODULE-LABEL: sil @object_with_unknown_callers3
|
||||
// MOVE: [[I:%[0-9]+]] = ref_element_addr %0 : $C, #C.i
|
||||
// MOVE: [[AI:%[0-9]+]] = begin_access [modify] [static] [[I]] : $*Int64
|
||||
// MOVE: [[TI:%[0-9]+]] = alloc_stack $Int64
|
||||
// MOVE: copy_addr [take] [[AI]] to [init] [[TI]] : $*Int64
|
||||
// MOVE: address_to_pointer [stack_protection] [[TI]]
|
||||
// MOVE: [[J:%[0-9]+]] = ref_element_addr %0 : $C, #C.j
|
||||
// MOVE: [[AJ:%[0-9]+]] = begin_access [modify] [static] [[J]] : $*Int64
|
||||
// MOVE: [[TJ:%[0-9]+]] = alloc_stack $Int64
|
||||
// MOVE: copy_addr [take] [[AJ]] to [init] [[TJ]] : $*Int64
|
||||
// MOVE: copy_addr [take] [[TI]] to [init] [[AI]] : $*Int64
|
||||
// MOVE: end_access [[AI]] : $*Int64
|
||||
// MOVE: address_to_pointer [stack_protection] [[TJ]]
|
||||
// MOVE: copy_addr [take] [[TJ]] to [init] [[AJ]] : $*Int64
|
||||
// MOVE: dealloc_stack [[TJ]] : $*Int64
|
||||
// MOVE: dealloc_stack [[TI]] : $*Int64
|
||||
// MOVE: end_access [[AJ]] : $*Int64
|
||||
// MODULE-NOT: alloc_stack
|
||||
// MODULE-NOT: copy_addr
|
||||
// CHECK: } // end sil function 'object_with_unknown_callers3'
|
||||
sil @object_with_unknown_callers3 : $@convention(thin) (@guaranteed C) -> () {
|
||||
bb0(%0 : $C):
|
||||
@@ -257,10 +275,8 @@ bb0(%0 : $C):
|
||||
return %r : $()
|
||||
}
|
||||
|
||||
// MODULE-LABEL: sil hidden @known_callers_inout
|
||||
// FUNCTION-LABEL: sil hidden [stack_protection] @known_callers_inout
|
||||
// MODULE-NOT: copy_addr
|
||||
// FUNCTION: copy_addr
|
||||
// CHECK-LABEL: sil hidden @known_callers_inout
|
||||
// CHECK-NOT: copy_addr
|
||||
// CHECK: } // end sil function 'known_callers_inout'
|
||||
sil hidden @known_callers_inout : $@convention(thin) (@inout Int64) -> () {
|
||||
bb0(%0 : $*Int64):
|
||||
@@ -315,9 +331,11 @@ bb3:
|
||||
return %4 : $()
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil hidden [stack_protection] @unknown_callers
|
||||
// CHECK: copy_addr
|
||||
// CHECK: copy_addr
|
||||
// MOVE-LABEL: sil hidden [stack_protection] @unknown_callers
|
||||
// MODULE-LABEL: sil hidden @unknown_callers
|
||||
// MOVE: copy_addr
|
||||
// MOVE: copy_addr
|
||||
// MODULE-NOT: copy_addr
|
||||
// CHECK: } // end sil function 'unknown_callers'
|
||||
sil hidden @unknown_callers : $@convention(thin) (@inout Int64) -> () {
|
||||
bb0(%0 : $*Int64):
|
||||
@@ -341,10 +359,35 @@ bb0(%0 : $*Int64):
|
||||
return %4 : $()
|
||||
}
|
||||
|
||||
// MODULE-LABEL: sil hidden @known_callers_obj1
|
||||
// FUNCTION-LABEL: sil hidden [stack_protection] @known_callers_obj1
|
||||
// MOVE-LABEL: sil [stack_protection] @partially_known_callers
|
||||
// MODULE-LABEL: sil @partially_known_callers
|
||||
// MOVE: copy_addr
|
||||
// MOVE: copy_addr
|
||||
// MODULE-NOT: copy_addr
|
||||
// FUNCTION: copy_addr
|
||||
// CHECK: } // end sil function 'partially_known_callers'
|
||||
sil @partially_known_callers : $@convention(thin) (@inout Int64) -> () {
|
||||
bb0(%0 : $*Int64):
|
||||
%1 = address_to_pointer [stack_protection] %0 : $*Int64 to $Builtin.RawPointer
|
||||
%2 = tuple ()
|
||||
return %2 : $()
|
||||
}
|
||||
|
||||
// MOVE-LABEL: sil @call_partially_known_callers
|
||||
// MODULE-LABEL: sil [stack_protection] @call_partially_known_callers
|
||||
// CHECK-NOT: copy_addr
|
||||
// CHECK: } // end sil function 'call_partially_known_callers'
|
||||
sil @call_partially_known_callers : $@convention(thin) () -> () {
|
||||
bb0:
|
||||
%0 = alloc_stack $Int64
|
||||
%1 = function_ref @partially_known_callers : $@convention(thin) (@inout Int64) -> ()
|
||||
%2 = apply %1(%0) : $@convention(thin) (@inout Int64) -> ()
|
||||
dealloc_stack %0 : $*Int64
|
||||
%4 = tuple ()
|
||||
return %4 : $()
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil hidden @known_callers_obj1
|
||||
// CHECK-NOT: copy_addr
|
||||
// CHECK: } // end sil function 'known_callers_obj1'
|
||||
sil hidden @known_callers_obj1 : $@convention(thin) (@guaranteed C) -> () {
|
||||
bb0(%0 : $C):
|
||||
@@ -390,10 +433,12 @@ bb3(%5 : $C):
|
||||
return %r : $()
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil hidden [stack_protection] @known_callers_obj2
|
||||
// CHECK: alloc_stack
|
||||
// CHECK: copy_addr
|
||||
// CHECK: copy_addr
|
||||
// MOVE-LABEL: sil hidden [stack_protection] @known_callers_obj2
|
||||
// MODULE-LABEL: sil hidden @known_callers_obj2
|
||||
// MOVE: alloc_stack
|
||||
// MOVE: copy_addr
|
||||
// MOVE: copy_addr
|
||||
// MODULE-NOT: copy_addr
|
||||
// CHECK: } // end sil function 'known_callers_obj2'
|
||||
sil hidden @known_callers_obj2 : $@convention(thin) (@guaranteed C) -> () {
|
||||
bb0(%0 : $C):
|
||||
@@ -428,10 +473,8 @@ bb3(%5 : $C):
|
||||
return %r : $()
|
||||
}
|
||||
|
||||
// MODULE-LABEL: sil private @closure_with_inout_capture
|
||||
// FUNCTION-LABEL: sil private [stack_protection] @closure_with_inout_capture
|
||||
// MODULE-NOT: copy_addr
|
||||
// FUNCTION: copy_addr
|
||||
// CHECK-LABEL: sil private @closure_with_inout_capture
|
||||
// CHECK-NOT: copy_addr
|
||||
// CHECK: } // end sil function 'closure_with_inout_capture'
|
||||
sil private @closure_with_inout_capture : $@convention(thin) (@inout_aliasable Int64) -> () {
|
||||
bb0(%0 : $*Int64):
|
||||
@@ -464,10 +507,12 @@ bb0:
|
||||
return %12 : $()
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil private [stack_protection] @closure_with_inout_arg
|
||||
// CHECK: alloc_stack
|
||||
// CHECK: copy_addr
|
||||
// CHECK: copy_addr
|
||||
// MOVE-LABEL: sil private [stack_protection] @closure_with_inout_arg
|
||||
// MODULE-LABEL: sil private @closure_with_inout_arg
|
||||
// MOVE: alloc_stack
|
||||
// MOVE: copy_addr
|
||||
// MOVE: copy_addr
|
||||
// MODULE-NOT: copy_addr
|
||||
// CHECK: } // end sil function 'closure_with_inout_arg'
|
||||
sil private @closure_with_inout_arg : $@convention(thin) (@inout Int64) -> () {
|
||||
bb0(%0 : $*Int64):
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// RUN: %target-swift-frontend -module-name=test -emit-sil %s -O -enable-stack-protector | %FileCheck %s
|
||||
// RUN: %target-swift-frontend -module-name=test -emit-sil %s -O | %FileCheck %s --check-prefix=CHECK --check-prefix=DEFAULT
|
||||
// RUN: %target-swift-frontend -module-name=test -enable-move-inout-stack-protector -emit-sil %s -O -enable-stack-protector | %FileCheck %s --check-prefix=CHECK --check-prefix=MOVE
|
||||
|
||||
// REQUIRES: swift_in_compiler
|
||||
|
||||
@@ -71,9 +72,11 @@ public func callOverflowInoutPointer() {
|
||||
inoutWithKnownCaller(&x)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil [stack_protection] @$s4test22inoutWithUnknownCalleryySizF
|
||||
// CHECK: copy_addr [take] {{.*}} to [init]
|
||||
// CHECK: copy_addr [take] {{.*}} to [init]
|
||||
// DEFAULT-LABEL: sil @$s4test22inoutWithUnknownCalleryySizF
|
||||
// MOVE-LABEL: sil [stack_protection] @$s4test22inoutWithUnknownCalleryySizF
|
||||
// MOVE: copy_addr [take] {{.*}} to [init]
|
||||
// MOVE: copy_addr [take] {{.*}} to [init]
|
||||
// DEFAULT-NOT: copy_addr
|
||||
// CHECK: } // end sil function '$s4test22inoutWithUnknownCalleryySizF'
|
||||
public func inoutWithUnknownCaller(_ x: inout Int) {
|
||||
withUnsafeMutablePointer(to: &x) {
|
||||
|
||||
@@ -148,6 +148,10 @@ static llvm::cl::opt<bool>
|
||||
EnableSpeculativeDevirtualization("enable-spec-devirt",
|
||||
llvm::cl::desc("Enable Speculative Devirtualization pass."));
|
||||
|
||||
static llvm::cl::opt<bool>
|
||||
EnableMoveInoutStackProtection("enable-move-inout-stack-protector",
|
||||
llvm::cl::desc("Enable the stack protector by moving values to temporaries."));
|
||||
|
||||
static llvm::cl::opt<bool> EnableOSSAModules(
|
||||
"enable-ossa-modules",
|
||||
llvm::cl::desc("Do we always serialize SIL in OSSA form? If "
|
||||
@@ -607,6 +611,7 @@ int main(int argc, char **argv) {
|
||||
SILOpts.checkSILModuleLeaks = true;
|
||||
SILOpts.EnablePerformanceAnnotations = true;
|
||||
SILOpts.EnableStackProtection = true;
|
||||
SILOpts.EnableMoveInoutStackProtection = EnableMoveInoutStackProtection;
|
||||
|
||||
SILOpts.VerifyExclusivity = VerifyExclusivity;
|
||||
if (EnforceExclusivity.getNumOccurrences() != 0) {
|
||||
|
||||
Reference in New Issue
Block a user