6363#include " clang/AST/Decl.h"
6464#include " clang/AST/DeclCXX.h"
6565#include " clang/AST/DeclObjCCommon.h"
66+ #include " clang/AST/DeclTemplate.h"
6667#include " clang/AST/Expr.h"
6768#include " clang/AST/PrettyPrinter.h"
6869#include " clang/AST/RecordLayout.h"
@@ -4194,6 +4195,20 @@ namespace {
41944195 return false ;
41954196 }
41964197
4198+ static bool canTypeMutateBuffer (clang::QualType ty) {
4199+ // FIXME: better way to detect if a type can mutate the underlying buffer.
4200+ if (const auto *rd = ty->getAsRecordDecl ()) {
4201+ if (rd->isInStdNamespace () && rd->getName () == " span" )
4202+ return !cast<clang::ClassTemplateSpecializationDecl>(rd)
4203+ ->getTemplateArgs ()
4204+ .get (0 )
4205+ .getAsType ()
4206+ .isConstQualified ();
4207+ }
4208+ // Conservatively assume most types can mutate the underlying buffer.
4209+ return true ;
4210+ }
4211+
41974212 void addLifetimeDependencies (const clang::FunctionDecl *decl,
41984213 AbstractFunctionDecl *result) {
41994214 if (decl->getTemplatedKind () == clang::FunctionDecl::TK_FunctionTemplate)
@@ -4205,12 +4220,23 @@ namespace {
42054220 !isa<clang::CXXMethodDecl, clang::ObjCMethodDecl>(decl))
42064221 return ;
42074222
4223+ bool hasSkippedLifetimeAnnotation = false ;
42084224 auto isEscapable = [this ](clang::QualType ty) {
42094225 return evaluateOrDefault (
42104226 Impl.SwiftContext .evaluator ,
42114227 ClangTypeEscapability ({ty.getTypePtr (), &Impl}),
42124228 CxxEscapability::Unknown) != CxxEscapability::NonEscapable;
42134229 };
4230+ auto importedAsClass = [this ](clang::QualType ty, bool forSelf) {
4231+ if (!forSelf) {
4232+ if (ty->getPointeeType ().isNull ())
4233+ return false ;
4234+ ty = ty->getPointeeType ();
4235+ }
4236+ if (const auto *rd = ty->getAsRecordDecl ())
4237+ return recordHasReferenceSemantics (rd);
4238+ return false ;
4239+ };
42144240
42154241 auto swiftParams = result->getParameters ();
42164242 bool hasSelf =
@@ -4237,6 +4263,7 @@ namespace {
42374263 }
42384264
42394265 auto retType = decl->getReturnType ();
4266+ bool retMayMutateBuffer = canTypeMutateBuffer (retType);
42404267 auto warnForEscapableReturnType = [&] {
42414268 if (isEscapableAnnotatedType (retType.getTypePtr ())) {
42424269 Impl.addImportDiagnostic (
@@ -4252,8 +4279,11 @@ namespace {
42524279 SmallBitVector scopedLifetimeParamIndicesForReturn (dependencyVecSize);
42534280 SmallBitVector paramHasAnnotation (dependencyVecSize);
42544281 std::map<unsigned , SmallBitVector> inheritedArgDependences;
4255- auto processLifetimeBound = [&](unsigned idx, clang::QualType ty) {
4282+ auto processLifetimeBound = [&](unsigned idx, clang::QualType ty,
4283+ bool forSelf = false ) {
42564284 warnForEscapableReturnType ();
4285+ if (retMayMutateBuffer && importedAsClass (ty, forSelf))
4286+ hasSkippedLifetimeAnnotation = true ;
42574287 paramHasAnnotation[idx] = true ;
42584288 if (isEscapable (ty))
42594289 scopedLifetimeParamIndicesForReturn[idx] = true ;
@@ -4302,7 +4332,8 @@ namespace {
43024332 if (getImplicitObjectParamAnnotation<clang::LifetimeBoundAttr>(decl))
43034333 processLifetimeBound (
43044334 result->getSelfIndex (),
4305- cast<clang::CXXMethodDecl>(decl)->getThisType ()->getPointeeType ());
4335+ cast<clang::CXXMethodDecl>(decl)->getThisType ()->getPointeeType (),
4336+ /* forSelf=*/ true );
43064337 if (auto attr =
43074338 getImplicitObjectParamAnnotation<clang::LifetimeCaptureByAttr>(
43084339 decl))
@@ -4352,16 +4383,21 @@ namespace {
43524383 Impl.SwiftContext .AllocateCopy (lifetimeDependencies));
43534384 }
43544385
4355- for (auto [idx, param] : llvm::enumerate (decl->parameters ())) {
4356- if (isEscapable (param->getType ()))
4357- continue ;
4358- if (param->hasAttr <clang::NoEscapeAttr>() || paramHasAnnotation[idx])
4359- continue ;
4360- // We have a nonescapable parameter that does not have its lifetime
4361- // annotated nor is it marked noescape.
4386+ if (hasSkippedLifetimeAnnotation) {
43624387 auto attr = new (ASTContext) UnsafeAttr (/* implicit=*/ true );
43634388 result->getAttrs ().add (attr);
4364- break ;
4389+ } else {
4390+ for (auto [idx, param] : llvm::enumerate (decl->parameters ())) {
4391+ if (isEscapable (param->getType ()))
4392+ continue ;
4393+ if (param->hasAttr <clang::NoEscapeAttr>() || paramHasAnnotation[idx])
4394+ continue ;
4395+ // We have a nonescapable parameter that does not have its lifetime
4396+ // annotated nor is it marked noescape.
4397+ auto attr = new (ASTContext) UnsafeAttr (/* implicit=*/ true );
4398+ result->getAttrs ().add (attr);
4399+ break ;
4400+ }
43654401 }
43664402
43674403 Impl.diagnoseTargetDirectly (decl);
@@ -9546,13 +9582,22 @@ void ClangImporter::Implementation::swiftify(AbstractFunctionDecl *MappedDecl) {
95469582 SIW_DBG (" Found bounds info '" << clang::QualType (CAT, 0 ) << " ' on return value\n " );
95479583 attachMacro = true ;
95489584 }
9585+ auto requiresExclusiveClassDependency = [](ParamDecl *fromParam,
9586+ clang::QualType toType) {
9587+ return fromParam->getInterfaceType ()->isAnyClassReferenceType () &&
9588+ SwiftDeclConverter::canTypeMutateBuffer (toType);
9589+ };
95499590 bool returnHasLifetimeInfo = false ;
95509591 if (SwiftDeclConverter::getImplicitObjectParamAnnotation<
95519592 clang::LifetimeBoundAttr>(ClangDecl)) {
95529593 SIW_DBG (" Found lifetimebound attribute on implicit 'this'\n " );
9553- printer.printLifetimeboundReturn (SwiftifyInfoPrinter::SELF_PARAM_INDEX,
9554- true );
9555- returnHasLifetimeInfo = true ;
9594+ if (!requiresExclusiveClassDependency (
9595+ MappedDecl->getImplicitSelfDecl (/* createIfNeeded*/ true ),
9596+ ClangDecl->getReturnType ())) {
9597+ printer.printLifetimeboundReturn (SwiftifyInfoPrinter::SELF_PARAM_INDEX,
9598+ true );
9599+ returnHasLifetimeInfo = true ;
9600+ }
95569601 }
95579602
95589603 bool isClangInstanceMethod =
@@ -9609,14 +9654,18 @@ void ClangImporter::Implementation::swiftify(AbstractFunctionDecl *MappedDecl) {
96099654 if (clangParam->hasAttr <clang::LifetimeBoundAttr>()) {
96109655 SIW_DBG (" Found lifetimebound attribute on parameter '"
96119656 << *clangParam << " '\n " );
9612- // If this parameter has bounds info we will tranform it into a Span,
9613- // so then it will no longer be Escapable.
9614- bool willBeEscapable = swiftParamTy->isEscapable () &&
9615- (!paramHasBoundsInfo ||
9616- mappedIndex == SwiftifyInfoPrinter::SELF_PARAM_INDEX);
9617- printer.printLifetimeboundReturn (mappedIndex, willBeEscapable);
9618- paramHasLifetimeInfo = true ;
9619- returnHasLifetimeInfo = true ;
9657+ if (!requiresExclusiveClassDependency (swiftParam,
9658+ ClangDecl->getReturnType ())) {
9659+ // If this parameter has bounds info we will tranform it into a Span,
9660+ // so then it will no longer be Escapable.
9661+ bool willBeEscapable =
9662+ swiftParamTy->isEscapable () &&
9663+ (!paramHasBoundsInfo ||
9664+ mappedIndex == SwiftifyInfoPrinter::SELF_PARAM_INDEX);
9665+ printer.printLifetimeboundReturn (mappedIndex, willBeEscapable);
9666+ paramHasLifetimeInfo = true ;
9667+ returnHasLifetimeInfo = true ;
9668+ }
96209669 }
96219670 if (paramIsStdSpan && paramHasLifetimeInfo) {
96229671 SIW_DBG (" Found both std::span and lifetime info "
0 commit comments