Skip to content

Commit 795d629

Browse files
authored
Merge pull request #78771 from swiftlang/gaborh/unsafe-lifetime-unannotated
[cxx-interop] Require lifetime annotations in safe mode
2 parents 190779e + 0a38617 commit 795d629

File tree

2 files changed

+31
-2
lines changed

2 files changed

+31
-2
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3980,8 +3980,8 @@ namespace {
39803980
if (decl->getTemplatedKind() == clang::FunctionDecl::TK_FunctionTemplate)
39813981
return;
39823982

3983-
if (!result->getASTContext().LangOpts.hasFeature(
3984-
Feature::LifetimeDependence))
3983+
auto &ASTContext = result->getASTContext();
3984+
if (!ASTContext.LangOpts.hasFeature(Feature::LifetimeDependence))
39853985
return;
39863986

39873987
SmallVector<LifetimeDependenceInfo, 1> lifetimeDependencies;
@@ -4013,9 +4013,11 @@ namespace {
40134013
const auto dependencyVecSize = swiftParams->size() + hasSelf;
40144014
SmallBitVector inheritLifetimeParamIndicesForReturn(dependencyVecSize);
40154015
SmallBitVector scopedLifetimeParamIndicesForReturn(dependencyVecSize);
4016+
SmallBitVector paramHasAnnotation(dependencyVecSize);
40164017
std::map<unsigned, SmallBitVector> inheritedArgDependences;
40174018
auto processLifetimeBound = [&](unsigned idx, Type ty) {
40184019
warnForEscapableReturnType();
4020+
paramHasAnnotation[idx] = true;
40194021
if (ty->isEscapable())
40204022
scopedLifetimeParamIndicesForReturn[idx] = true;
40214023
else
@@ -4039,6 +4041,7 @@ namespace {
40394041
param == clang::LifetimeCaptureByAttr::INVALID)
40404042
continue;
40414043

4044+
paramHasAnnotation[idx] = true;
40424045
if (isa<clang::CXXMethodDecl>(decl) &&
40434046
param == clang::LifetimeCaptureByAttr::THIS) {
40444047
auto [it, inserted] = inheritedArgDependences.try_emplace(
@@ -4110,6 +4113,19 @@ namespace {
41104113
LifetimeDependenceInfoRequest{result},
41114114
Impl.SwiftContext.AllocateCopy(lifetimeDependencies));
41124115
}
4116+
if (ASTContext.LangOpts.hasFeature(Feature::AllowUnsafeAttribute) &&
4117+
ASTContext.LangOpts.hasFeature(Feature::SafeInterop)) {
4118+
for (auto [idx, param] : llvm::enumerate(decl->parameters())) {
4119+
if (swiftParams->get(idx)->getInterfaceType()->isEscapable())
4120+
continue;
4121+
if (param->hasAttr<clang::NoEscapeAttr>() || paramHasAnnotation[idx])
4122+
continue;
4123+
// We have a nonescapabe parameter that does not have its lifetime
4124+
// annotated nor is it marked noescape.
4125+
auto attr = new (ASTContext) UnsafeAttr(/*implicit=*/true);
4126+
result->getAttrs().add(attr);
4127+
}
4128+
}
41134129
Impl.diagnoseTargetDirectly(decl);
41144130
}
41154131

test/Interop/Cxx/class/safe-interop-mode.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ using VecOfInt = std::vector<int>;
6161
using SafeTuple = std::tuple<int, int, int>;
6262
using UnsafeTuple = std::tuple<int, int*, int>;
6363

64+
View safeFunc(View v1 [[clang::noescape]], View v2 [[clang::lifetimebound]]);
65+
// Second non-escapable type is not annotated in any way.
66+
void unsafeFunc(View v1 [[clang::noescape]], View v2);
67+
6468
//--- test.swift
6569

6670
import Test
@@ -112,3 +116,12 @@ func useCppSpan(x: SpanOfInt) { // expected-note{{reference to unsafe type alias
112116
// expected-warning@+1{{global function 'useCppSpan2' has an interface that is not memory-safe}}
113117
func useCppSpan2(x: SpanOfIntAlias) { // expected-note{{reference to unsafe type alias 'SpanOfIntAlias'}}
114118
}
119+
120+
func useSafeLifetimeAnnotated(v: View) {
121+
let _ = safeFunc(v, v)
122+
}
123+
124+
func useUnsafeLifetimeAnnotated(v: View) {
125+
// expected-warning@+1{{expression uses unsafe constructs but is not marked with 'unsafe'}}
126+
unsafeFunc(v, v) // expected-note{{reference to unsafe global function 'unsafeFunc'}}
127+
}

0 commit comments

Comments
 (0)