@@ -5053,13 +5053,22 @@ synthesizeBaseClassMethodBody(AbstractFunctionDecl *afd, void *context) {
5053
5053
return {body, /* isTypeChecked=*/ true };
5054
5054
}
5055
5055
5056
+ // How should the synthesized C++ method that returns the field of interest
5057
+ // from the base class should return the value - by value, or by reference.
5058
+ enum ReferenceReturnTypeBehaviorForBaseAccessorSynthesis {
5059
+ ReturnByValue,
5060
+ ReturnByReference,
5061
+ ReturnByMutableReference
5062
+ };
5063
+
5056
5064
// Synthesize a C++ method that returns the field of interest from the base
5057
5065
// class. This lets Clang take care of the cast from the derived class
5058
5066
// to the base class while the field is accessed.
5059
5067
static clang::CXXMethodDecl *synthesizeCxxBaseGetterAccessorMethod (
5060
5068
ClangImporter &impl, const clang::CXXRecordDecl *derivedClass,
5061
5069
const clang::CXXRecordDecl *baseClass, const clang::FieldDecl *field,
5062
- ValueDecl *retainOperationFn) {
5070
+ ValueDecl *retainOperationFn,
5071
+ ReferenceReturnTypeBehaviorForBaseAccessorSynthesis behavior) {
5063
5072
auto &clangCtx = impl.getClangASTContext ();
5064
5073
auto &clangSema = impl.getClangSema ();
5065
5074
@@ -5068,16 +5077,30 @@ static clang::CXXMethodDecl *synthesizeCxxBaseGetterAccessorMethod(
5068
5077
if (name.isIdentifier ()) {
5069
5078
std::string newName;
5070
5079
llvm::raw_string_ostream os (newName);
5071
- os << " __synthesizedBaseGetterAccessor_"
5080
+ os << (behavior == ReferenceReturnTypeBehaviorForBaseAccessorSynthesis::
5081
+ ReturnByMutableReference
5082
+ ? " __synthesizedBaseSetterAccessor_"
5083
+ : " __synthesizedBaseGetterAccessor_" )
5072
5084
<< name.getAsIdentifierInfo ()->getName ();
5073
5085
name = clang::DeclarationName (
5074
5086
&impl.getClangPreprocessor ().getIdentifierTable ().get (os.str ()));
5075
5087
}
5076
5088
auto returnType = field->getType ();
5077
5089
if (returnType->isReferenceType ())
5078
5090
returnType = returnType->getPointeeType ();
5091
+ auto valueReturnType = returnType;
5092
+ if (behavior !=
5093
+ ReferenceReturnTypeBehaviorForBaseAccessorSynthesis::ReturnByValue) {
5094
+ returnType = clangCtx.getRValueReferenceType (
5095
+ behavior == ReferenceReturnTypeBehaviorForBaseAccessorSynthesis::
5096
+ ReturnByReference
5097
+ ? returnType.withConst ()
5098
+ : returnType);
5099
+ }
5079
5100
clang::FunctionProtoType::ExtProtoInfo info;
5080
- info.TypeQuals .addConst ();
5101
+ if (behavior != ReferenceReturnTypeBehaviorForBaseAccessorSynthesis::
5102
+ ReturnByMutableReference)
5103
+ info.TypeQuals .addConst ();
5081
5104
info.ExceptionSpec .Type = clang::EST_NoThrow;
5082
5105
auto ftype = clangCtx.getFunctionType (returnType, {}, info);
5083
5106
auto newMethod = clang::CXXMethodDecl::Create (
@@ -5128,9 +5151,10 @@ static clang::CXXMethodDecl *synthesizeCxxBaseGetterAccessorMethod(
5128
5151
/* HadMultipleCandidates=*/ false ,
5129
5152
clang::DeclarationNameInfo (field->getDeclName (),
5130
5153
clang::SourceLocation ()),
5131
- returnType, clang::VK_LValue, clang::OK_Ordinary);
5132
- auto returnCast = clangSema.ImpCastExprToType (
5133
- memberExpr, returnType, clang::CK_LValueToRValue, clang::VK_PRValue);
5154
+ valueReturnType, clang::VK_LValue, clang::OK_Ordinary);
5155
+ auto returnCast = clangSema.ImpCastExprToType (memberExpr, valueReturnType,
5156
+ clang::CK_LValueToRValue,
5157
+ clang::VK_PRValue);
5134
5158
if (!returnCast.isUsable ())
5135
5159
return nullptr ;
5136
5160
return returnCast.get ();
@@ -5187,7 +5211,11 @@ static clang::CXXMethodDecl *synthesizeCxxBaseGetterAccessorMethod(
5187
5211
// The method's body takes the following form:
5188
5212
// return self.__synthesizedBaseCall_fn(args...)
5189
5213
static std::pair<BraceStmt *, bool >
5190
- synthesizeBaseClassFieldGetterBody (AbstractFunctionDecl *afd, void *context) {
5214
+ synthesizeBaseClassFieldGetterOrAddressGetterBody (AbstractFunctionDecl *afd,
5215
+ void *context,
5216
+ AccessorKind kind) {
5217
+ assert (kind == AccessorKind::Get || kind == AccessorKind::Address ||
5218
+ kind == AccessorKind::MutableAddress);
5191
5219
ASTContext &ctx = afd->getASTContext ();
5192
5220
5193
5221
AccessorDecl *getterDecl = cast<AccessorDecl>(afd);
@@ -5201,8 +5229,7 @@ synthesizeBaseClassFieldGetterBody(AbstractFunctionDecl *afd, void *context) {
5201
5229
if (baseClassVar->getClangDecl ())
5202
5230
baseClangDecl = baseClassVar->getClangDecl ();
5203
5231
else
5204
- baseClangDecl =
5205
- getCalledBaseCxxMethod (baseClassVar->getAccessor (AccessorKind::Get));
5232
+ baseClangDecl = getCalledBaseCxxMethod (baseClassVar->getAccessor (kind));
5206
5233
5207
5234
clang::CXXMethodDecl *baseGetterCxxMethod = nullptr ;
5208
5235
if (auto *md = dyn_cast_or_null<clang::CXXMethodDecl>(baseClangDecl)) {
@@ -5215,9 +5242,12 @@ synthesizeBaseClassFieldGetterBody(AbstractFunctionDecl *afd, void *context) {
5215
5242
getterDecl->getResultInterfaceType ()->isForeignReferenceType ()
5216
5243
? ReferenceReturnTypeBehaviorForBaseMethodSynthesis::
5217
5244
RemoveReferenceIfPointer
5218
- : ReferenceReturnTypeBehaviorForBaseMethodSynthesis::
5219
- RemoveReference,
5220
- /* forceConstQualifier=*/ true );
5245
+ : (kind != AccessorKind::Get
5246
+ ? ReferenceReturnTypeBehaviorForBaseMethodSynthesis::
5247
+ KeepReference
5248
+ : ReferenceReturnTypeBehaviorForBaseMethodSynthesis::
5249
+ RemoveReference),
5250
+ /* forceConstQualifier=*/ kind != AccessorKind::MutableAddress);
5221
5251
} else if (auto *fd = dyn_cast_or_null<clang::FieldDecl>(baseClangDecl)) {
5222
5252
ValueDecl *retainOperationFn = nullptr ;
5223
5253
// Check if this field getter is returning a retainable FRT.
@@ -5240,7 +5270,14 @@ synthesizeBaseClassFieldGetterBody(AbstractFunctionDecl *afd, void *context) {
5240
5270
*static_cast <ClangImporter *>(ctx.getClangModuleLoader ()),
5241
5271
cast<clang::CXXRecordDecl>(derivedStruct->getClangDecl ()),
5242
5272
cast<clang::CXXRecordDecl>(baseStruct->getClangDecl ()), fd,
5243
- retainOperationFn);
5273
+ retainOperationFn,
5274
+ kind == AccessorKind::Get
5275
+ ? ReferenceReturnTypeBehaviorForBaseAccessorSynthesis::ReturnByValue
5276
+ : (kind == AccessorKind::Address
5277
+ ? ReferenceReturnTypeBehaviorForBaseAccessorSynthesis::
5278
+ ReturnByReference
5279
+ : ReferenceReturnTypeBehaviorForBaseAccessorSynthesis::
5280
+ ReturnByMutableReference));
5244
5281
}
5245
5282
5246
5283
if (!baseGetterCxxMethod) {
@@ -5253,12 +5290,17 @@ synthesizeBaseClassFieldGetterBody(AbstractFunctionDecl *afd, void *context) {
5253
5290
auto *baseGetterMethod = cast<FuncDecl>(
5254
5291
ctx.getClangModuleLoader ()->importDeclDirectly (baseGetterCxxMethod));
5255
5292
5256
- auto selfDecl = getterDecl->getImplicitSelfDecl ();
5257
- auto selfExpr = new (ctx) DeclRefExpr (selfDecl, DeclNameLoc (),
5258
- /* implicit*/ true );
5259
- selfExpr->setType (selfDecl->getTypeInContext ());
5260
-
5261
- Argument selfArg = Argument::unlabeled (selfExpr);
5293
+ Argument selfArg = [&]() {
5294
+ auto selfDecl = getterDecl->getImplicitSelfDecl ();
5295
+ auto selfExpr = new (ctx) DeclRefExpr (selfDecl, DeclNameLoc (),
5296
+ /* implicit*/ true );
5297
+ if (kind == AccessorKind::MutableAddress) {
5298
+ selfExpr->setType (LValueType::get (selfDecl->getInterfaceType ()));
5299
+ return Argument::implicitInOut (ctx, selfExpr);
5300
+ }
5301
+ selfExpr->setType (selfDecl->getTypeInContext ());
5302
+ return Argument::unlabeled (selfExpr);
5303
+ }();
5262
5304
5263
5305
auto *baseMemberExpr =
5264
5306
new (ctx) DeclRefExpr (ConcreteDeclRef (baseGetterMethod), DeclNameLoc (),
@@ -5294,6 +5336,19 @@ synthesizeBaseClassFieldGetterBody(AbstractFunctionDecl *afd, void *context) {
5294
5336
return {body, /* isTypeChecked=*/ true };
5295
5337
}
5296
5338
5339
+ static std::pair<BraceStmt *, bool >
5340
+ synthesizeBaseClassFieldGetterBody (AbstractFunctionDecl *afd, void *context) {
5341
+ return synthesizeBaseClassFieldGetterOrAddressGetterBody (afd, context,
5342
+ AccessorKind::Get);
5343
+ }
5344
+
5345
+ static std::pair<BraceStmt *, bool >
5346
+ synthesizeBaseClassFieldAddressGetterBody (AbstractFunctionDecl *afd,
5347
+ void *context) {
5348
+ return synthesizeBaseClassFieldGetterOrAddressGetterBody (
5349
+ afd, context, AccessorKind::Address);
5350
+ }
5351
+
5297
5352
// For setters we have to pass self as a pointer and then emit an assign:
5298
5353
// %0 = Builtin.addressof(&self)
5299
5354
// %1 = Builtin.reinterpretCast<UnsafeMutablePointer<Derived>>(%0)
@@ -5355,13 +5410,24 @@ synthesizeBaseClassFieldSetterBody(AbstractFunctionDecl *afd, void *context) {
5355
5410
return {body, /* isTypeChecked=*/ true };
5356
5411
}
5357
5412
5413
+ static std::pair<BraceStmt *, bool >
5414
+ synthesizeBaseClassFieldAddressSetterBody (AbstractFunctionDecl *afd,
5415
+ void *context) {
5416
+ return synthesizeBaseClassFieldGetterOrAddressGetterBody (
5417
+ afd, context, AccessorKind::MutableAddress);
5418
+ }
5419
+
5358
5420
static SmallVector<AccessorDecl *, 2 >
5359
5421
makeBaseClassMemberAccessors (DeclContext *declContext,
5360
5422
AbstractStorageDecl *computedVar,
5361
5423
AbstractStorageDecl *baseClassVar) {
5362
5424
auto &ctx = declContext->getASTContext ();
5363
5425
auto computedType = computedVar->getInterfaceType ();
5364
5426
5427
+ // Use 'address' or 'mutableAddress' accessors for non-copyable
5428
+ // types.
5429
+ bool useAddress = computedType->isNoncopyable (declContext);
5430
+
5365
5431
ParameterList *bodyParams = nullptr ;
5366
5432
if (auto subscript = dyn_cast<SubscriptDecl>(baseClassVar)) {
5367
5433
computedType = computedType->getAs <FunctionType>()->getResult ();
@@ -5375,18 +5441,22 @@ makeBaseClassMemberAccessors(DeclContext *declContext,
5375
5441
auto getterDecl = AccessorDecl::create (
5376
5442
ctx,
5377
5443
/* FuncLoc=*/ SourceLoc (),
5378
- /* AccessorKeywordLoc=*/ SourceLoc (), AccessorKind::Get, computedVar,
5444
+ /* AccessorKeywordLoc=*/ SourceLoc (),
5445
+ useAddress ? AccessorKind::Address : AccessorKind::Get, computedVar,
5379
5446
/* StaticLoc=*/ SourceLoc (),
5380
5447
StaticSpellingKind::None, // TODO: we should handle static vars.
5381
5448
/* Async=*/ false , /* AsyncLoc=*/ SourceLoc (),
5382
5449
/* Throws=*/ false ,
5383
- /* ThrowsLoc=*/ SourceLoc (), /* ThrownType=*/ TypeLoc (),
5384
- bodyParams, computedType, declContext);
5450
+ /* ThrowsLoc=*/ SourceLoc (), /* ThrownType=*/ TypeLoc (), bodyParams,
5451
+ useAddress ? computedType->wrapInPointer (PTK_UnsafePointer)
5452
+ : computedType,
5453
+ declContext);
5385
5454
getterDecl->setIsTransparent (true );
5386
5455
getterDecl->setAccess (AccessLevel::Public);
5387
- getterDecl->setBodySynthesizer (synthesizeBaseClassFieldGetterBody,
5456
+ getterDecl->setBodySynthesizer (useAddress
5457
+ ? synthesizeBaseClassFieldAddressGetterBody
5458
+ : synthesizeBaseClassFieldGetterBody,
5388
5459
baseClassVar);
5389
-
5390
5460
if (baseClassVar->getWriteImpl () == WriteImplKind::Immutable)
5391
5461
return {getterDecl};
5392
5462
@@ -5396,28 +5466,33 @@ makeBaseClassMemberAccessors(DeclContext *declContext,
5396
5466
newValueParam->setSpecifier (ParamSpecifier::Default);
5397
5467
newValueParam->setInterfaceType (computedType);
5398
5468
5399
- ParameterList *setterBodyParams = nullptr ;
5400
- if (auto subscript = dyn_cast<SubscriptDecl>(baseClassVar)) {
5401
- auto idxParam = subscript->getIndices ()->get (0 );
5402
- bodyParams = ParameterList::create (ctx, { idxParam });
5403
- setterBodyParams = ParameterList::create (ctx, { newValueParam, idxParam });
5404
- } else {
5405
- setterBodyParams = ParameterList::create (ctx, { newValueParam });
5406
- }
5469
+ SmallVector<ParamDecl *, 2 > setterParamDecls;
5470
+ if (!useAddress)
5471
+ setterParamDecls.push_back (newValueParam);
5472
+ if (auto subscript = dyn_cast<SubscriptDecl>(baseClassVar))
5473
+ setterParamDecls.push_back (subscript->getIndices ()->get (0 ));
5474
+ ParameterList *setterBodyParams =
5475
+ ParameterList::create (ctx, setterParamDecls);
5407
5476
5408
5477
auto setterDecl = AccessorDecl::create (
5409
5478
ctx,
5410
5479
/* FuncLoc=*/ SourceLoc (),
5411
- /* AccessorKeywordLoc=*/ SourceLoc (), AccessorKind::Set, computedVar,
5480
+ /* AccessorKeywordLoc=*/ SourceLoc (),
5481
+ useAddress ? AccessorKind::MutableAddress : AccessorKind::Set,
5482
+ computedVar,
5412
5483
/* StaticLoc=*/ SourceLoc (),
5413
5484
StaticSpellingKind::None, // TODO: we should handle static vars.
5414
5485
/* Async=*/ false , /* AsyncLoc=*/ SourceLoc (),
5415
5486
/* Throws=*/ false ,
5416
- /* ThrowsLoc=*/ SourceLoc (), /* ThrownType=*/ TypeLoc (),
5417
- setterBodyParams, TupleType::getEmpty (ctx),declContext);
5487
+ /* ThrowsLoc=*/ SourceLoc (), /* ThrownType=*/ TypeLoc (), setterBodyParams,
5488
+ useAddress ? computedType->wrapInPointer (PTK_UnsafeMutablePointer)
5489
+ : TupleType::getEmpty (ctx),
5490
+ declContext);
5418
5491
setterDecl->setIsTransparent (true );
5419
5492
setterDecl->setAccess (AccessLevel::Public);
5420
- setterDecl->setBodySynthesizer (synthesizeBaseClassFieldSetterBody,
5493
+ setterDecl->setBodySynthesizer (useAddress
5494
+ ? synthesizeBaseClassFieldAddressSetterBody
5495
+ : synthesizeBaseClassFieldSetterBody,
5421
5496
baseClassVar);
5422
5497
setterDecl->setSelfAccessKind (SelfAccessKind::Mutating);
5423
5498
@@ -5504,6 +5579,10 @@ cloneBaseMemberDecl(ValueDecl *decl, DeclContext *newContext) {
5504
5579
}
5505
5580
5506
5581
if (auto subscript = dyn_cast<SubscriptDecl>(decl)) {
5582
+ // Subscripts that return non-copyable types are not yet supported.
5583
+ // See: https://github.com/apple/swift/issues/70047.
5584
+ if (subscript->getElementInterfaceType ()->isNoncopyable (newContext))
5585
+ return nullptr ;
5507
5586
auto out = SubscriptDecl::create (
5508
5587
subscript->getASTContext (), subscript->getName (), subscript->getStaticLoc (),
5509
5588
subscript->getStaticSpelling (), subscript->getSubscriptLoc (),
@@ -5528,12 +5607,17 @@ cloneBaseMemberDecl(ValueDecl *decl, DeclContext *newContext) {
5528
5607
out->setIsDynamic (var->isDynamic ());
5529
5608
out->copyFormalAccessFrom (var);
5530
5609
out->getASTContext ().evaluator .cacheOutput (HasStorageRequest{out}, false );
5531
- out->setAccessors (SourceLoc (),
5532
- makeBaseClassMemberAccessors (newContext, out, var),
5533
- SourceLoc ());
5610
+ auto accessors = makeBaseClassMemberAccessors (newContext, out, var);
5611
+ out->setAccessors (SourceLoc (), accessors, SourceLoc ());
5534
5612
auto isMutable = var->getWriteImpl () == WriteImplKind::Immutable
5535
5613
? StorageIsNotMutable : StorageIsMutable;
5536
- out->setImplInfo (StorageImplInfo::getComputed (isMutable));
5614
+ out->setImplInfo (
5615
+ accessors[0 ]->getAccessorKind () == AccessorKind::Address
5616
+ ? (accessors[1 ] ? StorageImplInfo (ReadImplKind::Address,
5617
+ WriteImplKind::MutableAddress,
5618
+ ReadWriteImplKind::MutableAddress)
5619
+ : StorageImplInfo (ReadImplKind::Address))
5620
+ : StorageImplInfo::getComputed (isMutable));
5537
5621
out->setIsSetterMutating (true );
5538
5622
return out;
5539
5623
}
0 commit comments