Skip to content

Commit df05add

Browse files
authored
Merge pull request #79552 from hnrklssn/swiftify-span-with-counted-by
[ClangImporter][Swiftify] merge importBoundsAttributes with importSpanAttributes and support lifetime bounds for __counted_by - [ClangImporter] Merge paths for std::span and __counted_by importBoundsAttributes and importSpanAttributes are merged into a single function named swiftify. This allows us to not have to duplicate the effort of attaching _SwiftifyImport macros, but is also necessary to allow importing a function with both __counted_by and std::span types. - [ClangImporter] Enable parsing bounds safety attributes in C++ This allows combining __counted_by and std::span for safe interop. Previously we disabled this in C++ mode due to issues when bounds attributes occurred directly or indirectly in templated contexts, but this has now been resolved on the clang side. - [Swiftify] Emit Span for counted_by return values with lifetime info __counted_by return values with .lifetimeDependence are now mapped to Span instead of UnsafeBufferPointer. Also fixes bug where std::span return values would map to Span even if lifetime dependence info was missing.
2 parents 38cbdf8 + afe86b6 commit df05add

File tree

10 files changed

+212
-161
lines changed

10 files changed

+212
-161
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -566,8 +566,7 @@ void importer::getNormalInvocationArguments(
566566
}
567567
}
568568

569-
if (LangOpts.hasFeature(Feature::SafeInteropWrappers) &&
570-
!LangOpts.EnableCXXInterop)
569+
if (LangOpts.hasFeature(Feature::SafeInteropWrappers))
571570
invocationArgStrs.push_back("-fexperimental-bounds-safety-attributes");
572571

573572
// Set C language options.

lib/ClangImporter/ImportDecl.cpp

Lines changed: 73 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,7 @@ createFuncOrAccessor(ClangImporter::Implementation &impl, SourceLoc funcLoc,
114114
std::optional<AccessorInfo> accessorInfo, DeclName name,
115115
SourceLoc nameLoc, GenericParamList *genericParams,
116116
ParameterList *bodyParams, Type resultTy, bool async,
117-
bool throws, DeclContext *dc, ClangNode clangNode,
118-
bool hasBoundsAnnotation) {
117+
bool throws, DeclContext *dc, ClangNode clangNode) {
119118
FuncDecl *decl;
120119
if (accessorInfo) {
121120
decl = AccessorDecl::create(
@@ -131,9 +130,7 @@ createFuncOrAccessor(ClangImporter::Implementation &impl, SourceLoc funcLoc,
131130
genericParams, dc, clangNode);
132131
}
133132
impl.importSwiftAttrAttributes(decl);
134-
if (hasBoundsAnnotation)
135-
impl.importBoundsAttributes(decl);
136-
impl.importSpanAttributes(decl);
133+
impl.swiftify(decl);
137134

138135
return decl;
139136
}
@@ -3381,8 +3378,7 @@ namespace {
33813378
}
33823379
return Impl.importFunctionParameterList(
33833380
dc, decl, nonSelfParams, decl->isVariadic(), allowNSUIntegerAsInt,
3384-
argNames, genericParams, /*resultType=*/nullptr,
3385-
/*hasBoundsAnnotatedParam=*/nullptr);
3381+
argNames, genericParams, /*resultType=*/nullptr);
33863382
}
33873383

33883384
Decl *
@@ -3812,7 +3808,6 @@ namespace {
38123808

38133809
bool importFuncWithoutSignature =
38143810
isa<clang::CXXMethodDecl>(decl) && Impl.importSymbolicCXXDecls;
3815-
bool hasBoundsAnnotation = false;
38163811
if (!dc->isModuleScopeContext() && !isa<clang::CXXMethodDecl>(decl)) {
38173812
// Handle initializers.
38183813
if (name.getBaseName().isConstructor()) {
@@ -3909,7 +3904,7 @@ namespace {
39093904
importedType = Impl.importFunctionParamsAndReturnType(
39103905
dc, decl, {decl->param_begin(), decl->param_size()},
39113906
decl->isVariadic(), isInSystemModule(dc), name, bodyParams,
3912-
templateParams, &hasBoundsAnnotation);
3907+
templateParams);
39133908
}
39143909

39153910
if (auto *mdecl = dyn_cast<clang::CXXMethodDecl>(decl)) {
@@ -3975,11 +3970,10 @@ namespace {
39753970
} else {
39763971
auto resultTy = importedType.getType();
39773972

3978-
FuncDecl *func =
3979-
createFuncOrAccessor(Impl, loc, accessorInfo, name, nameLoc,
3980-
genericParams, bodyParams, resultTy,
3981-
/*async=*/false, /*throws=*/false, dc,
3982-
clangNode, hasBoundsAnnotation);
3973+
FuncDecl *func = createFuncOrAccessor(
3974+
Impl, loc, accessorInfo, name, nameLoc, genericParams, bodyParams,
3975+
resultTy,
3976+
/*async=*/false, /*throws=*/false, dc, clangNode);
39833977
result = func;
39843978

39853979
if (!dc->isModuleScopeContext()) {
@@ -5068,14 +5062,12 @@ namespace {
50685062
}
50695063
}
50705064

5071-
bool hasBoundsAnnotation =
5072-
false; // currently only implemented for functions
5073-
auto result = createFuncOrAccessor(
5074-
Impl,
5075-
/*funcLoc*/ SourceLoc(), accessorInfo, importedName.getDeclName(),
5076-
/*nameLoc*/ SourceLoc(),
5077-
/*genericParams=*/nullptr, bodyParams, resultTy, async, throws, dc,
5078-
decl, hasBoundsAnnotation);
5065+
auto result = createFuncOrAccessor(Impl,
5066+
/*funcLoc*/ SourceLoc(), accessorInfo,
5067+
importedName.getDeclName(),
5068+
/*nameLoc*/ SourceLoc(),
5069+
/*genericParams=*/nullptr, bodyParams,
5070+
resultTy, async, throws, dc, decl);
50795071

50805072
result->setAccess(decl->isDirectMethod() ? AccessLevel::Public
50815073
: getOverridableAccessLevel(dc));
@@ -6737,7 +6729,7 @@ Decl *SwiftDeclConverter::importGlobalAsInitializer(
67376729
parameterList = Impl.importFunctionParameterList(
67386730
dc, decl, {decl->param_begin(), decl->param_end()}, decl->isVariadic(),
67396731
allowNSUIntegerAsInt, argNames, /*genericParams=*/{},
6740-
/*resultType=*/nullptr, /*hasBoundsAnnotatedParam=*/nullptr);
6732+
/*resultType=*/nullptr);
67416733

67426734
if (name && parameterList && argNames.size() != parameterList->size()) {
67436735
// Remember that the name has changed.
@@ -8828,6 +8820,8 @@ ClangImporter::Implementation::importSwiftAttrAttributes(Decl *MappedDecl) {
88288820
namespace {
88298821
class SwiftifyInfoPrinter {
88308822
public:
8823+
static const ssize_t SELF_PARAM_INDEX = -2;
8824+
static const ssize_t RETURN_VALUE_INDEX = -1;
88318825
clang::ASTContext &ctx;
88328826
llvm::raw_ostream &out;
88338827
bool firstParam = true;
@@ -8899,17 +8893,17 @@ class SwiftifyInfoPrinter {
88998893
}
89008894

89018895
void printParamOrReturn(ssize_t pointerIndex) {
8902-
if (pointerIndex == -2)
8896+
if (pointerIndex == SELF_PARAM_INDEX)
89038897
out << ".self";
8904-
else if (pointerIndex == -1)
8898+
else if (pointerIndex == RETURN_VALUE_INDEX)
89058899
out << ".return";
89068900
else
89078901
out << ".param(" << pointerIndex + 1 << ")";
89088902
}
89098903
};
89108904
} // namespace
89118905

8912-
void ClangImporter::Implementation::importSpanAttributes(FuncDecl *MappedDecl) {
8906+
void ClangImporter::Implementation::swiftify(FuncDecl *MappedDecl) {
89138907
if (!SwiftContext.LangOpts.hasFeature(Feature::SafeInteropWrappers))
89148908
return;
89158909
auto ClangDecl =
@@ -8918,96 +8912,81 @@ void ClangImporter::Implementation::importSpanAttributes(FuncDecl *MappedDecl) {
89188912
return;
89198913

89208914
llvm::SmallString<128> MacroString;
8915+
// We only attach the macro if it will produce an overload. Any __counted_by
8916+
// will produce an overload, since UnsafeBufferPointer is still an improvement
8917+
// over UnsafePointer, but std::span will only produce an overload if it also
8918+
// has lifetime information, since std::span already contains bounds info.
89218919
bool attachMacro = false;
89228920
{
89238921
llvm::raw_svector_ostream out(MacroString);
89248922
llvm::StringMap<std::string> typeMapping;
89258923

8926-
auto registerSwiftifyMacro =
8927-
[&typeMapping, &attachMacro](ParamDecl *swiftParam,
8928-
const clang::ParmVarDecl *param) {
8929-
typeMapping.insert(std::make_pair(
8930-
swiftParam->getInterfaceType()->getString(),
8931-
swiftParam->getInterfaceType()->getDesugaredType()->getString()));
8932-
attachMacro = true;
8924+
auto registerStdSpanTypeMapping =
8925+
[&typeMapping](Type swiftType, const clang::QualType clangType) {
8926+
const auto *decl = clangType->getAsTagDecl();
8927+
if (decl && decl->isInStdNamespace() && decl->getName() == "span") {
8928+
typeMapping.insert(
8929+
std::make_pair(swiftType->getString(),
8930+
swiftType->getDesugaredType()->getString()));
8931+
return true;
8932+
}
8933+
return false;
89338934
};
89348935
SwiftifyInfoPrinter printer(getClangASTContext(), out);
8935-
auto retDecl = ClangDecl->getReturnType()->getAsTagDecl();
8936-
bool returnIsSpan =
8937-
retDecl && retDecl->isInStdNamespace() && retDecl->getName() == "span";
8938-
if (returnIsSpan) {
8939-
typeMapping.insert(
8940-
std::make_pair(MappedDecl->getResultInterfaceType()->getString(),
8941-
MappedDecl->getResultInterfaceType()
8942-
->getDesugaredType()
8943-
->getString()));
8944-
}
8945-
bool lifetimeDependenceOn = MappedDecl->getASTContext().LangOpts.hasFeature(
8946-
Feature::LifetimeDependence);
8936+
bool returnIsStdSpan = registerStdSpanTypeMapping(
8937+
MappedDecl->getResultInterfaceType(), ClangDecl->getReturnType());
8938+
if (auto CAT =
8939+
ClangDecl->getReturnType()->getAs<clang::CountAttributedType>()) {
8940+
printer.printCountedBy(CAT, SwiftifyInfoPrinter::RETURN_VALUE_INDEX);
8941+
attachMacro = true;
8942+
}
8943+
bool returnHasLifetimeInfo = false;
8944+
bool lifetimeDependenceOn =
8945+
SwiftContext.LangOpts.hasFeature(Feature::LifetimeDependence);
89478946
if (SwiftDeclConverter::getImplicitObjectParamAnnotation<
89488947
clang::LifetimeBoundAttr>(ClangDecl) &&
8949-
lifetimeDependenceOn && returnIsSpan) {
8950-
printer.printLifetimeboundReturn(-2, true);
8951-
attachMacro = true;
8948+
lifetimeDependenceOn) {
8949+
printer.printLifetimeboundReturn(SwiftifyInfoPrinter::SELF_PARAM_INDEX,
8950+
true);
8951+
returnHasLifetimeInfo = true;
89528952
}
8953-
for (auto [index, param] : llvm::enumerate(ClangDecl->parameters())) {
8954-
auto paramTy = param->getType();
8955-
const auto *decl = paramTy->getAsTagDecl();
8953+
for (auto [index, clangParam] : llvm::enumerate(ClangDecl->parameters())) {
8954+
auto clangParamTy = clangParam->getType();
89568955
auto swiftParam = MappedDecl->getParameters()->get(index);
8957-
bool isSpan =
8958-
decl && decl->isInStdNamespace() && decl->getName() == "span";
8959-
if (param->hasAttr<clang::LifetimeBoundAttr>() && lifetimeDependenceOn &&
8960-
(isSpan || returnIsSpan)) {
8961-
printer.printLifetimeboundReturn(
8962-
index, !isSpan && swiftParam->getInterfaceType()->isEscapable());
8963-
registerSwiftifyMacro(swiftParam, param);
8956+
bool paramHasBoundsInfo = false;
8957+
if (auto CAT = clangParamTy->getAs<clang::CountAttributedType>()) {
8958+
printer.printCountedBy(CAT, index);
8959+
attachMacro = paramHasBoundsInfo = true;
89648960
}
8965-
if (!isSpan)
8966-
continue;
8967-
if (param->hasAttr<clang::NoEscapeAttr>()) {
8961+
bool paramIsStdSpan = registerStdSpanTypeMapping(
8962+
swiftParam->getInterfaceType(), clangParamTy);
8963+
paramHasBoundsInfo |= paramIsStdSpan;
8964+
8965+
bool paramHasLifetimeInfo = false;
8966+
if (clangParam->hasAttr<clang::NoEscapeAttr>()) {
89688967
printer.printNonEscaping(index);
8969-
registerSwiftifyMacro(swiftParam, param);
8968+
paramHasLifetimeInfo = true;
89708969
}
8970+
if (clangParam->hasAttr<clang::LifetimeBoundAttr>() &&
8971+
lifetimeDependenceOn) {
8972+
printer.printLifetimeboundReturn(
8973+
index, !paramHasBoundsInfo &&
8974+
swiftParam->getInterfaceType()->isEscapable());
8975+
paramHasLifetimeInfo = true;
8976+
returnHasLifetimeInfo = true;
8977+
}
8978+
if (paramIsStdSpan && paramHasLifetimeInfo)
8979+
attachMacro = true;
89718980
}
8981+
if (returnIsStdSpan && returnHasLifetimeInfo)
8982+
attachMacro = true;
89728983
printer.printTypeMapping(typeMapping);
89738984
}
89748985

89758986
if (attachMacro)
89768987
importNontrivialAttribute(MappedDecl, MacroString);
89778988
}
89788989

8979-
void ClangImporter::Implementation::importBoundsAttributes(
8980-
FuncDecl *MappedDecl) {
8981-
assert(SwiftContext.LangOpts.hasFeature(Feature::SafeInteropWrappers));
8982-
auto ClangDecl =
8983-
dyn_cast_or_null<clang::FunctionDecl>(MappedDecl->getClangDecl());
8984-
// any function with safe pointer imports should have a clang decl
8985-
assert(ClangDecl);
8986-
if (!ClangDecl)
8987-
return;
8988-
8989-
llvm::SmallString<128> MacroString;
8990-
{
8991-
llvm::raw_svector_ostream out(MacroString);
8992-
8993-
SwiftifyInfoPrinter printer(getClangASTContext(), out);
8994-
for (auto [index, param] : llvm::enumerate(ClangDecl->parameters())) {
8995-
if (auto CAT = param->getType()->getAs<clang::CountAttributedType>()) {
8996-
printer.printCountedBy(CAT, index);
8997-
if (param->hasAttr<clang::NoEscapeAttr>()) {
8998-
printer.printNonEscaping(index);
8999-
}
9000-
}
9001-
}
9002-
if (auto CAT =
9003-
ClangDecl->getReturnType()->getAs<clang::CountAttributedType>()) {
9004-
printer.printCountedBy(CAT, -1);
9005-
}
9006-
}
9007-
9008-
importNontrivialAttribute(MappedDecl, MacroString);
9009-
}
9010-
90118990
static bool isUsingMacroName(clang::SourceManager &SM,
90128991
clang::SourceLocation loc,
90138992
StringRef MacroName) {

0 commit comments

Comments
 (0)