Skip to content

Commit e1b3403

Browse files
committed
Remove funcsWithPointerBounds, add experimental langopt
Pass around hasSafePointer as a parameter flag instead, and only call importBoundsAttributes when the imported function has a parameter or return value with CountAttributedType. Enables importing bounds safety pointers using -enable-experimental-bounds-safety-interop rather than based on a compile time define.
1 parent f746b08 commit e1b3403

File tree

11 files changed

+102
-84
lines changed

11 files changed

+102
-84
lines changed

include/swift/Basic/LangOptions.h

+4
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,10 @@ namespace swift {
325325
/// disabled because it is not complete.
326326
bool EnableCXXInterop = false;
327327

328+
/// Enable C interop importing bounds safety and lifetime attributes to
329+
/// generate Swift wrappers with safe pointer types (experimental).
330+
bool EnableBoundsSafetyInterop = false;
331+
328332
/// The C++ interoperability source compatibility version. Defaults
329333
/// to the Swift language version.
330334
version::Version cxxInteropCompatVersion;

include/swift/Option/Options.td

+5
Original file line numberDiff line numberDiff line change
@@ -792,6 +792,11 @@ def enable_experimental_concise_pound_file : Flag<["-"],
792792
Flags<[FrontendOption, ModuleInterfaceOption]>,
793793
HelpText<"Enable experimental concise '#file' identifier">;
794794

795+
def enable_experimental_bounds_safety_interop :
796+
Flag<["-"], "enable-experimental-bounds-safety-interop">,
797+
Flags<[NoDriverOption, FrontendOption, HelpHidden, ModuleInterfaceOption]>,
798+
HelpText<"Enable experimental C bounds safety interop code generation and config directives">;
799+
795800
def enable_experimental_cxx_interop :
796801
Flag<["-"], "enable-experimental-cxx-interop">,
797802
Flags<[NoDriverOption, FrontendOption, HelpHidden, ModuleInterfaceOption]>,

lib/ClangImporter/ClangImporter.cpp

+2-3
Original file line numberDiff line numberDiff line change
@@ -578,9 +578,8 @@ void importer::getNormalInvocationArguments(
578578
}
579579
}
580580

581-
#ifdef SWIFT_ENABLE_EXPERIMENTAL_POINTER_BOUNDS
582-
invokationsArgStrs.push_back("-fexperimental-bounds-safety-attributes");
583-
#endif
581+
if (LangOpts.EnableBoundsSafetyInterop)
582+
invocationArgStrs.push_back("-fexperimental-bounds-safety-attributes");
584583

585584
// Set C language options.
586585
if (triple.isOSDarwin()) {

lib/ClangImporter/ImportDecl.cpp

+25-18
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@ createFuncOrAccessor(ClangImporter::Implementation &impl, SourceLoc funcLoc,
108108
std::optional<AccessorInfo> accessorInfo, DeclName name,
109109
SourceLoc nameLoc, GenericParamList *genericParams,
110110
ParameterList *bodyParams, Type resultTy, bool async,
111-
bool throws, DeclContext *dc, ClangNode clangNode) {
111+
bool throws, DeclContext *dc, ClangNode clangNode,
112+
bool hasSafePointer) {
112113
FuncDecl *decl;
113114
if (accessorInfo) {
114115
decl = AccessorDecl::create(
@@ -124,7 +125,9 @@ createFuncOrAccessor(ClangImporter::Implementation &impl, SourceLoc funcLoc,
124125
genericParams, dc, clangNode);
125126
}
126127
impl.importSwiftAttrAttributes(decl);
127-
impl.importBoundsAttributes(decl);
128+
if (hasSafePointer)
129+
impl.importBoundsAttributes(decl);
130+
128131
return decl;
129132
}
130133

@@ -3252,7 +3255,8 @@ namespace {
32523255
}
32533256
return Impl.importFunctionParameterList(
32543257
dc, decl, nonSelfParams, decl->isVariadic(), allowNSUIntegerAsInt,
3255-
argNames, genericParams, /*resultType=*/nullptr);
3258+
argNames, genericParams, /*resultType=*/nullptr,
3259+
/*hasSafePointerParam=*/nullptr);
32563260
}
32573261

32583262
Decl *
@@ -3633,6 +3637,7 @@ namespace {
36333637

36343638
bool importFuncWithoutSignature =
36353639
isa<clang::CXXMethodDecl>(decl) && Impl.importSymbolicCXXDecls;
3640+
bool hasSafePointer = false;
36363641
if (!dc->isModuleScopeContext() && !isa<clang::CXXMethodDecl>(decl)) {
36373642
// Handle initializers.
36383643
if (name.getBaseName().isConstructor()) {
@@ -3729,7 +3734,7 @@ namespace {
37293734
importedType = Impl.importFunctionParamsAndReturnType(
37303735
dc, decl, {decl->param_begin(), decl->param_size()},
37313736
decl->isVariadic(), isInSystemModule(dc), name, bodyParams,
3732-
templateParams);
3737+
templateParams, &hasSafePointer);
37333738
}
37343739

37353740
if (auto *mdecl = dyn_cast<clang::CXXMethodDecl>(decl)) {
@@ -3795,11 +3800,10 @@ namespace {
37953800
} else {
37963801
auto resultTy = importedType.getType();
37973802

3798-
FuncDecl *func =
3799-
createFuncOrAccessor(Impl, loc, accessorInfo, name,
3800-
nameLoc, genericParams, bodyParams, resultTy,
3801-
/*async=*/false, /*throws=*/false, dc,
3802-
clangNode);
3803+
FuncDecl *func = createFuncOrAccessor(
3804+
Impl, loc, accessorInfo, name, nameLoc, genericParams, bodyParams,
3805+
resultTy,
3806+
/*async=*/false, /*throws=*/false, dc, clangNode, hasSafePointer);
38033807
result = func;
38043808

38053809
if (!dc->isModuleScopeContext()) {
@@ -4842,12 +4846,13 @@ namespace {
48424846
}
48434847
}
48444848

4845-
auto result = createFuncOrAccessor(Impl,
4846-
/*funcLoc*/ SourceLoc(), accessorInfo,
4847-
importedName.getDeclName(),
4848-
/*nameLoc*/ SourceLoc(),
4849-
/*genericParams=*/nullptr, bodyParams,
4850-
resultTy, async, throws, dc, decl);
4849+
bool hasSafePointer = false; // currently only implemented for functions
4850+
auto result = createFuncOrAccessor(
4851+
Impl,
4852+
/*funcLoc*/ SourceLoc(), accessorInfo, importedName.getDeclName(),
4853+
/*nameLoc*/ SourceLoc(),
4854+
/*genericParams=*/nullptr, bodyParams, resultTy, async, throws, dc,
4855+
decl, hasSafePointer);
48514856

48524857
result->setAccess(decl->isDirectMethod() ? AccessLevel::Public
48534858
: getOverridableAccessLevel(dc));
@@ -6490,7 +6495,8 @@ Decl *SwiftDeclConverter::importGlobalAsInitializer(
64906495
} else {
64916496
parameterList = Impl.importFunctionParameterList(
64926497
dc, decl, {decl->param_begin(), decl->param_end()}, decl->isVariadic(),
6493-
allowNSUIntegerAsInt, argNames, /*genericParams=*/{}, /*resultType=*/nullptr);
6498+
allowNSUIntegerAsInt, argNames, /*genericParams=*/{},
6499+
/*resultType=*/nullptr, /*hasSafePointerParam=*/nullptr);
64946500
}
64956501
if (!parameterList)
64966502
return nullptr;
@@ -8550,12 +8556,13 @@ class PointerParamInfoPrinter {
85508556

85518557
void ClangImporter::Implementation::importBoundsAttributes(
85528558
FuncDecl *MappedDecl) {
8559+
assert(SwiftContext.LangOpts.EnableBoundsSafetyInterop);
85538560
auto ClangDecl =
85548561
dyn_cast_or_null<clang::FunctionDecl>(MappedDecl->getClangDecl());
8562+
// any function with safe pointer imports should have a clang decl
8563+
assert(ClangDecl);
85558564
if (!ClangDecl)
85568565
return;
8557-
if (!funcsWithPointerBounds.count(ClangDecl))
8558-
return;
85598566

85608567
llvm::SmallString<128> MacroString;
85618568
{

lib/ClangImporter/ImportType.cpp

+44-44
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ namespace {
216216
Bridgeability Bridging;
217217
const clang::FunctionType *CompletionHandlerType;
218218
std::optional<unsigned> CompletionHandlerErrorParamIndex;
219+
bool isSafePointer = false;
219220

220221
public:
221222
SwiftTypeConverter(ClangImporter::Implementation &impl,
@@ -238,6 +239,8 @@ namespace {
238239
return IR;
239240
}
240241

242+
bool hasSafePointer() { return isSafePointer; }
243+
241244
ImportResult VisitType(const Type*) = delete;
242245

243246
// TODO(https://github.com/apple/swift/issues/56206): Add support for dependent types.
@@ -412,13 +415,8 @@ namespace {
412415

413416
ImportResult VisitCountAttributedType(
414417
const clang::CountAttributedType *type) {
415-
// CountAttributedType is a clang type representing a pointer with
416-
// a "counted_by" type attribute. For now, we don't import these
417-
// into Swift.
418-
// In the future we could do something more clever (such as trying to
419-
// import as an Array where possible) or less clever (such as importing
420-
// as the desugared, underlying pointer type).
421-
return Type();
418+
isSafePointer = true;
419+
return Visit(type->desugar());
422420
}
423421

424422
ImportResult VisitMemberPointerType(const clang::MemberPointerType *type) {
@@ -470,7 +468,9 @@ namespace {
470468
// without special hints.
471469
Type pointeeType = Impl.importTypeIgnoreIUO(
472470
pointeeQualType, ImportTypeKind::Value, addImportDiagnostic,
473-
AllowNSUIntegerAsInt, Bridgeability::None, ImportTypeAttrs());
471+
AllowNSUIntegerAsInt, Bridgeability::None, ImportTypeAttrs(),
472+
OTK_ImplicitlyUnwrappedOptional, /*resugarNSErrorPointer=*/true,
473+
&isSafePointer);
474474

475475
// If this is imported as a reference type, ignore the innermost pointer.
476476
// (`T *` becomes `T`, but `T **` becomes `UnsafeMutablePointer<T>`.)
@@ -1699,7 +1699,8 @@ ImportedType ClangImporter::Implementation::importType(
16991699
llvm::function_ref<void(Diagnostic &&)> addImportDiagnosticFn,
17001700
bool allowNSUIntegerAsInt, Bridgeability bridging, ImportTypeAttrs attrs,
17011701
OptionalTypeKind optionality, bool resugarNSErrorPointer,
1702-
std::optional<unsigned> completionHandlerErrorParamIndex) {
1702+
std::optional<unsigned> completionHandlerErrorParamIndex,
1703+
bool *isSafePointer) {
17031704
if (type.isNull())
17041705
return {Type(), false};
17051706

@@ -1761,6 +1762,8 @@ ImportedType ClangImporter::Implementation::importType(
17611762
*this, addImportDiagnosticFn, allowNSUIntegerAsInt, bridging,
17621763
completionHandlerType, completionHandlerErrorParamIndex);
17631764
auto importResult = converter.Visit(type);
1765+
if (isSafePointer)
1766+
*isSafePointer |= converter.hasSafePointer();
17641767

17651768
// Now fix up the type based on how we're concretely using it.
17661769
auto adjustedType = adjustTypeForConcreteImport(
@@ -1774,13 +1777,13 @@ ImportedType ClangImporter::Implementation::importType(
17741777
Type ClangImporter::Implementation::importTypeIgnoreIUO(
17751778
clang::QualType type, ImportTypeKind importKind,
17761779
llvm::function_ref<void(Diagnostic &&)> addImportDiagnosticFn,
1777-
bool allowNSUIntegerAsInt, Bridgeability bridging,
1778-
ImportTypeAttrs attrs, OptionalTypeKind optionality,
1779-
bool resugarNSErrorPointer) {
1780+
bool allowNSUIntegerAsInt, Bridgeability bridging, ImportTypeAttrs attrs,
1781+
OptionalTypeKind optionality, bool resugarNSErrorPointer,
1782+
bool *isSafePointer) {
17801783

1781-
auto importedType = importType(type, importKind, addImportDiagnosticFn,
1782-
allowNSUIntegerAsInt, bridging, attrs,
1783-
optionality, resugarNSErrorPointer);
1784+
auto importedType = importType(
1785+
type, importKind, addImportDiagnosticFn, allowNSUIntegerAsInt, bridging,
1786+
attrs, optionality, resugarNSErrorPointer, std::nullopt, isSafePointer);
17841787

17851788
return importedType.getType();
17861789
}
@@ -2165,7 +2168,7 @@ applyImportTypeAttrs(ImportTypeAttrs attrs, Type type,
21652168

21662169
ImportedType ClangImporter::Implementation::importFunctionReturnType(
21672170
DeclContext *dc, const clang::FunctionDecl *clangDecl,
2168-
bool allowNSUIntegerAsInt) {
2171+
bool allowNSUIntegerAsInt, bool *isSafePointer) {
21692172

21702173
// Hardcode handling of certain result types for builtins.
21712174
if (auto builtinID = clangDecl->getBuiltinID()) {
@@ -2274,13 +2277,13 @@ ImportedType ClangImporter::Implementation::importFunctionReturnType(
22742277
}
22752278

22762279
// Import the result type.
2277-
return importType(returnType,
2278-
(isAuditedResult ? ImportTypeKind::AuditedResult
2279-
: ImportTypeKind::Result),
2280-
ImportDiagnosticAdder(*this, clangDecl,
2281-
clangDecl->getLocation()),
2282-
allowNSUIntegerAsInt, Bridgeability::Full,
2283-
getImportTypeAttrs(clangDecl), OptionalityOfReturn);
2280+
return importType(
2281+
returnType,
2282+
(isAuditedResult ? ImportTypeKind::AuditedResult
2283+
: ImportTypeKind::Result),
2284+
ImportDiagnosticAdder(*this, clangDecl, clangDecl->getLocation()),
2285+
allowNSUIntegerAsInt, Bridgeability::Full, getImportTypeAttrs(clangDecl),
2286+
OptionalityOfReturn, isSafePointer);
22842287
}
22852288

22862289
static Type
@@ -2315,7 +2318,7 @@ ImportedType ClangImporter::Implementation::importFunctionParamsAndReturnType(
23152318
DeclContext *dc, const clang::FunctionDecl *clangDecl,
23162319
ArrayRef<const clang::ParmVarDecl *> params, bool isVariadic,
23172320
bool isFromSystemModule, DeclName name, ParameterList *&parameterList,
2318-
ArrayRef<GenericTypeParamDecl *> genericParams) {
2321+
ArrayRef<GenericTypeParamDecl *> genericParams, bool *hasSafePointer) {
23192322

23202323
bool allowNSUIntegerAsInt =
23212324
shouldAllowNSUIntegerAsInt(isFromSystemModule, clangDecl);
@@ -2372,8 +2375,8 @@ ImportedType ClangImporter::Implementation::importFunctionParamsAndReturnType(
23722375
// If importedType is already initialized, it means we found the enum that
23732376
// was supposed to be used (instead of the typedef type).
23742377
if (!importedType) {
2375-
importedType =
2376-
importFunctionReturnType(dc, clangDecl, allowNSUIntegerAsInt);
2378+
importedType = importFunctionReturnType(
2379+
dc, clangDecl, allowNSUIntegerAsInt, hasSafePointer);
23772380
if (!importedType) {
23782381
addDiag(Diagnostic(diag::return_type_not_imported));
23792382
return {Type(), false};
@@ -2383,9 +2386,9 @@ ImportedType ClangImporter::Implementation::importFunctionParamsAndReturnType(
23832386

23842387
Type swiftResultTy = importedType.getType();
23852388
ArrayRef<Identifier> argNames = name.getArgumentNames();
2386-
parameterList = importFunctionParameterList(dc, clangDecl, params, isVariadic,
2387-
allowNSUIntegerAsInt, argNames,
2388-
genericParams, swiftResultTy);
2389+
parameterList = importFunctionParameterList(
2390+
dc, clangDecl, params, isVariadic, allowNSUIntegerAsInt, argNames,
2391+
genericParams, swiftResultTy, hasSafePointer);
23892392
if (!parameterList)
23902393
return {Type(), false};
23912394

@@ -2434,13 +2437,6 @@ ClangImporter::Implementation::importParameterType(
24342437
}
24352438
}
24362439
}
2437-
} else if (auto CAT = dyn_cast<clang::CountAttributedType>(paramTy)) {
2438-
// Treat as a normal pointer. importBoundsAttributes() will generate a safe
2439-
// overload later.
2440-
paramTy = CAT->desugar();
2441-
if (auto FuncD =
2442-
dyn_cast<clang::FunctionDecl>(param->getParentFunctionOrMethod()))
2443-
funcsWithPointerBounds.insert(FuncD);
24442440
} else if (isa<clang::PointerType>(paramTy) &&
24452441
isa<clang::TemplateTypeParmType>(paramTy->getPointeeType())) {
24462442
auto pointeeType = paramTy->getPointeeType();
@@ -2529,6 +2525,7 @@ ClangImporter::Implementation::importParameterType(
25292525
}
25302526
}
25312527

2528+
bool isSafePointer = false;
25322529
if (!swiftParamTy) {
25332530
// If this is the throws error parameter, we don't need to convert any
25342531
// NSError** arguments to the sugared NSErrorPointer typealias form,
@@ -2538,11 +2535,11 @@ ClangImporter::Implementation::importParameterType(
25382535
// for the specific case when the throws conversion works, but is not
25392536
// sufficient if it fails. (The correct, overarching fix is ClangImporter
25402537
// being lazier.)
2541-
auto importedType = importType(paramTy, importKind, addImportDiagnosticFn,
2542-
allowNSUIntegerAsInt, Bridgeability::Full,
2543-
attrs, optionalityOfParam,
2544-
/*resugarNSErrorPointer=*/!paramIsError,
2545-
completionHandlerErrorParamIndex);
2538+
auto importedType = importType(
2539+
paramTy, importKind, addImportDiagnosticFn, allowNSUIntegerAsInt,
2540+
Bridgeability::Full, attrs, optionalityOfParam,
2541+
/*resugarNSErrorPointer=*/!paramIsError,
2542+
completionHandlerErrorParamIndex, &isSafePointer);
25462543
if (!importedType)
25472544
return std::nullopt;
25482545

@@ -2559,8 +2556,8 @@ ClangImporter::Implementation::importParameterType(
25592556
if (isInOut && isDirectUseOfForeignReferenceType(paramTy, swiftParamTy))
25602557
isInOut = false;
25612558

2562-
return ImportParameterTypeResult{swiftParamTy, isInOut,
2563-
isParamTypeImplicitlyUnwrapped};
2559+
return ImportParameterTypeResult{
2560+
swiftParamTy, isInOut, isParamTypeImplicitlyUnwrapped, isSafePointer};
25642561
}
25652562

25662563
bool ClangImporter::Implementation::isDefaultArgSafeToImport(
@@ -2671,7 +2668,8 @@ ParameterList *ClangImporter::Implementation::importFunctionParameterList(
26712668
DeclContext *dc, const clang::FunctionDecl *clangDecl,
26722669
ArrayRef<const clang::ParmVarDecl *> params, bool isVariadic,
26732670
bool allowNSUIntegerAsInt, ArrayRef<Identifier> argNames,
2674-
ArrayRef<GenericTypeParamDecl *> genericParams, Type resultType) {
2671+
ArrayRef<GenericTypeParamDecl *> genericParams, Type resultType,
2672+
bool *hasSafePointerParam) {
26752673
// Import the parameters.
26762674
SmallVector<ParamDecl *, 4> parameters;
26772675
unsigned index = 0;
@@ -2711,6 +2709,8 @@ ParameterList *ClangImporter::Implementation::importFunctionParameterList(
27112709
bool isInOut = swiftParamTyOpt->isInOut;
27122710
bool isParamTypeImplicitlyUnwrapped =
27132711
swiftParamTyOpt->isParamTypeImplicitlyUnwrapped;
2712+
if (swiftParamTyOpt->isSafePointer && hasSafePointerParam)
2713+
*hasSafePointerParam = true;
27142714

27152715
// Retrieve the argument name.
27162716
Identifier name;

0 commit comments

Comments
 (0)