@@ -4891,187 +4891,6 @@ MemberRefExpr *getSelfInteropStaticCast(FuncDecl *funcDecl,
4891
4891
return pointeePropertyRefExpr;
4892
4892
}
4893
4893
4894
- enum class ReferenceReturnTypeBehaviorForBaseMethodSynthesis {
4895
- KeepReference,
4896
- RemoveReference,
4897
- RemoveReferenceIfPointer,
4898
- };
4899
-
4900
- // Synthesize a C++ method that invokes the method from the base
4901
- // class. This lets Clang take care of the cast from the derived class
4902
- // to the base class during the invocation of the method.
4903
- static clang::CXXMethodDecl *synthesizeCxxBaseMethod (
4904
- ClangImporter &impl, const clang::CXXRecordDecl *derivedClass,
4905
- const clang::CXXRecordDecl *baseClass, const clang::CXXMethodDecl *method,
4906
- ReferenceReturnTypeBehaviorForBaseMethodSynthesis
4907
- referenceReturnTypeBehavior =
4908
- ReferenceReturnTypeBehaviorForBaseMethodSynthesis::KeepReference,
4909
- bool forceConstQualifier = false ,
4910
- bool isVirtualCall = false ) {
4911
- auto &clangCtx = impl.getClangASTContext ();
4912
- auto &clangSema = impl.getClangSema ();
4913
- // When emitting symbolic decls, the method might not have a concrete
4914
- // record type as this type.
4915
- if (impl.isSymbolicImportEnabled ()
4916
- && !method->getThisType ()->getPointeeCXXRecordDecl ()) {
4917
- return nullptr ;
4918
- }
4919
-
4920
- // Create a new method in the derived class that calls the base method.
4921
- clang::DeclarationName name = method->getNameInfo ().getName ();
4922
- if (name.isIdentifier ()) {
4923
- std::string newName;
4924
- llvm::raw_string_ostream os (newName);
4925
- os << (isVirtualCall ? " __synthesizedVirtualCall_" :
4926
- " __synthesizedBaseCall_" )
4927
- << name.getAsIdentifierInfo ()->getName ();
4928
- name = clang::DeclarationName (
4929
- &impl.getClangPreprocessor ().getIdentifierTable ().get (os.str ()));
4930
- } else if (name.getCXXOverloadedOperator () == clang::OO_Subscript) {
4931
- name = clang::DeclarationName (
4932
- &impl.getClangPreprocessor ().getIdentifierTable ().get (
4933
- (isVirtualCall ? " __synthesizedVirtualCall_operatorSubscript" :
4934
- " __synthesizedBaseCall_operatorSubscript" )));
4935
- } else if (name.getCXXOverloadedOperator () == clang::OO_Star) {
4936
- name = clang::DeclarationName (
4937
- &impl.getClangPreprocessor ().getIdentifierTable ().get (
4938
- (isVirtualCall ? " __synthesizedVirtualCall_operatorStar" :
4939
- " __synthesizedBaseCall_operatorStar" )));
4940
- }
4941
- auto methodType = method->getType ();
4942
- // Check if we need to drop the reference from the return type
4943
- // of the new method. This is needed when a synthesized `operator []`
4944
- // derived-to-base call is invoked from Swift's subscript getter.
4945
- if (referenceReturnTypeBehavior !=
4946
- ReferenceReturnTypeBehaviorForBaseMethodSynthesis::KeepReference) {
4947
- if (const auto *fpt = methodType->getAs <clang::FunctionProtoType>()) {
4948
- auto retType = fpt->getReturnType ();
4949
- if (retType->isReferenceType () &&
4950
- (referenceReturnTypeBehavior ==
4951
- ReferenceReturnTypeBehaviorForBaseMethodSynthesis::
4952
- RemoveReference ||
4953
- (referenceReturnTypeBehavior ==
4954
- ReferenceReturnTypeBehaviorForBaseMethodSynthesis::
4955
- RemoveReferenceIfPointer &&
4956
- retType->getPointeeType ()->isPointerType ()))) {
4957
- methodType = clangCtx.getFunctionType (retType->getPointeeType (),
4958
- fpt->getParamTypes (),
4959
- fpt->getExtProtoInfo ());
4960
- }
4961
- }
4962
- }
4963
- // Check if this method requires an additional `const` qualifier.
4964
- // This might needed when a non-const synthesized `operator []`
4965
- // derived-to-base call is invoked from Swift's subscript getter.
4966
- bool castThisToNonConstThis = false ;
4967
- if (forceConstQualifier) {
4968
- if (const auto *fpt = methodType->getAs <clang::FunctionProtoType>()) {
4969
- auto info = fpt->getExtProtoInfo ();
4970
- if (!info.TypeQuals .hasConst ()) {
4971
- info.TypeQuals .addConst ();
4972
- castThisToNonConstThis = true ;
4973
- methodType = clangCtx.getFunctionType (fpt->getReturnType (),
4974
- fpt->getParamTypes (), info);
4975
- }
4976
- }
4977
- }
4978
- auto newMethod = clang::CXXMethodDecl::Create (
4979
- clangCtx, const_cast <clang::CXXRecordDecl *>(derivedClass),
4980
- method->getSourceRange ().getBegin (),
4981
- clang::DeclarationNameInfo (name, clang::SourceLocation ()), methodType,
4982
- method->getTypeSourceInfo (), method->getStorageClass (),
4983
- method->UsesFPIntrin (), /* isInline=*/ true , method->getConstexprKind (),
4984
- method->getSourceRange ().getEnd ());
4985
- newMethod->setImplicit ();
4986
- newMethod->setImplicitlyInline ();
4987
- newMethod->setAccess (clang::AccessSpecifier::AS_public);
4988
- if (method->hasAttr <clang::CFReturnsRetainedAttr>()) {
4989
- // Return an FRT field at +1 if the base method also follows this
4990
- // convention.
4991
- newMethod->addAttr (clang::CFReturnsRetainedAttr::CreateImplicit (clangCtx));
4992
- }
4993
-
4994
- llvm::SmallVector<clang::ParmVarDecl *, 4 > params;
4995
- for (size_t i = 0 ; i < method->getNumParams (); ++i) {
4996
- const auto ¶m = *method->getParamDecl (i);
4997
- params.push_back (clang::ParmVarDecl::Create (
4998
- clangCtx, newMethod, param.getSourceRange ().getBegin (),
4999
- param.getLocation (), param.getIdentifier (), param.getType (),
5000
- param.getTypeSourceInfo (), param.getStorageClass (),
5001
- /* DefExpr=*/ nullptr ));
5002
- }
5003
- newMethod->setParams (params);
5004
-
5005
- // Create a new Clang diagnostic pool to capture any diagnostics
5006
- // emitted during the construction of the method.
5007
- clang::sema::DelayedDiagnosticPool diagPool{
5008
- clangSema.DelayedDiagnostics .getCurrentPool ()};
5009
- auto diagState = clangSema.DelayedDiagnostics .push (diagPool);
5010
-
5011
- // Construct the method's body.
5012
- clang::Expr *thisExpr = new (clangCtx) clang::CXXThisExpr (
5013
- clang::SourceLocation (), newMethod->getThisType (), /* IsImplicit=*/ false );
5014
- if (castThisToNonConstThis) {
5015
- auto baseClassPtr =
5016
- clangCtx.getPointerType (clangCtx.getRecordType (derivedClass));
5017
- clang::CastKind Kind;
5018
- clang::CXXCastPath Path;
5019
- clangSema.CheckPointerConversion (thisExpr, baseClassPtr, Kind, Path,
5020
- /* IgnoreBaseAccess=*/ false ,
5021
- /* Diagnose=*/ true );
5022
- auto conv = clangSema.ImpCastExprToType (thisExpr, baseClassPtr, Kind,
5023
- clang::VK_PRValue, &Path);
5024
- if (!conv.isUsable ())
5025
- return nullptr ;
5026
- thisExpr = conv.get ();
5027
- }
5028
-
5029
- auto memberExpr = clangSema.BuildMemberExpr (
5030
- thisExpr, /* isArrow=*/ true , clang::SourceLocation (),
5031
- clang::NestedNameSpecifierLoc (), clang::SourceLocation (),
5032
- const_cast <clang::CXXMethodDecl *>(method),
5033
- clang::DeclAccessPair::make (const_cast <clang::CXXMethodDecl *>(method),
5034
- clang::AS_public),
5035
- /* HadMultipleCandidates=*/ false , method->getNameInfo (),
5036
- clangCtx.BoundMemberTy , clang::VK_PRValue, clang::OK_Ordinary);
5037
- llvm::SmallVector<clang::Expr *, 4 > args;
5038
- for (size_t i = 0 ; i < newMethod->getNumParams (); ++i) {
5039
- auto *param = newMethod->getParamDecl (i);
5040
- auto type = param->getType ();
5041
- if (type->isReferenceType ())
5042
- type = type->getPointeeType ();
5043
- args.push_back (new (clangCtx) clang::DeclRefExpr (
5044
- clangCtx, param, false , type, clang::ExprValueKind::VK_LValue,
5045
- clang::SourceLocation ()));
5046
- }
5047
- auto memberCall = clangSema.BuildCallToMemberFunction (
5048
- nullptr , memberExpr, clang::SourceLocation (), args,
5049
- clang::SourceLocation ());
5050
- if (!memberCall.isUsable ())
5051
- return nullptr ;
5052
- auto returnStmt = clang::ReturnStmt::Create (clangCtx, clang::SourceLocation (),
5053
- memberCall.get (), nullptr );
5054
-
5055
- // Check if there were any Clang errors during the construction
5056
- // of the method body.
5057
- clangSema.DelayedDiagnostics .popWithoutEmitting (diagState);
5058
- if (!diagPool.empty ())
5059
- return nullptr ;
5060
-
5061
- newMethod->setBody (returnStmt);
5062
- return newMethod;
5063
- }
5064
-
5065
- // Synthesize a C++ virtual method
5066
- clang::CXXMethodDecl *synthesizeCxxVirtualMethod (
5067
- swift::ClangImporter &Impl, const clang::CXXRecordDecl *derivedClass,
5068
- const clang::CXXRecordDecl *baseClass, const clang::CXXMethodDecl *method) {
5069
- return synthesizeCxxBaseMethod (
5070
- Impl, derivedClass, baseClass, method,
5071
- ReferenceReturnTypeBehaviorForBaseMethodSynthesis::KeepReference,
5072
- false /* forceConstQualifier */ , true /* isVirtualCall */ );
5073
- }
5074
-
5075
4894
// Find the base C++ method called by the base function we want to synthesize
5076
4895
// the derived thunk for.
5077
4896
// The base C++ method is either the original C++ method that corresponds
@@ -5127,9 +4946,11 @@ FuncDecl *synthesizeBaseFunctionDeclCall(ClangImporter &impl, ASTContext &ctx,
5127
4946
auto *cxxMethod = getCalledBaseCxxMethod (baseMember);
5128
4947
if (!cxxMethod)
5129
4948
return nullptr ;
5130
- auto *newClangMethod = synthesizeCxxBaseMethod (
5131
- impl, cast<clang::CXXRecordDecl>(derivedStruct->getClangDecl ()),
5132
- cast<clang::CXXRecordDecl>(baseStruct->getClangDecl ()), cxxMethod);
4949
+ auto *newClangMethod =
4950
+ SwiftDeclSynthesizer (&impl).synthesizeCXXForwardingMethod (
4951
+ cast<clang::CXXRecordDecl>(derivedStruct->getClangDecl ()),
4952
+ cast<clang::CXXRecordDecl>(baseStruct->getClangDecl ()), cxxMethod,
4953
+ ForwardingMethodKind::Base);
5133
4954
if (!newClangMethod)
5134
4955
return nullptr ;
5135
4956
return cast_or_null<FuncDecl>(
@@ -5388,19 +5209,22 @@ synthesizeBaseClassFieldGetterOrAddressGetterBody(AbstractFunctionDecl *afd,
5388
5209
if (auto *md = dyn_cast_or_null<clang::CXXMethodDecl>(baseClangDecl)) {
5389
5210
// Subscript operator, or `.pointee` wrapper is represented through a
5390
5211
// generated C++ method call that calls the base operator.
5391
- baseGetterCxxMethod = synthesizeCxxBaseMethod (
5392
- *static_cast <ClangImporter *>(ctx.getClangModuleLoader ()),
5393
- cast<clang::CXXRecordDecl>(derivedStruct->getClangDecl ()),
5394
- cast<clang::CXXRecordDecl>(baseStruct->getClangDecl ()), md,
5395
- getterDecl->getResultInterfaceType ()->isForeignReferenceType ()
5396
- ? ReferenceReturnTypeBehaviorForBaseMethodSynthesis::
5397
- RemoveReferenceIfPointer
5398
- : (kind != AccessorKind::Get
5399
- ? ReferenceReturnTypeBehaviorForBaseMethodSynthesis::
5400
- KeepReference
5401
- : ReferenceReturnTypeBehaviorForBaseMethodSynthesis::
5402
- RemoveReference),
5403
- /* forceConstQualifier=*/ kind != AccessorKind::MutableAddress);
5212
+ baseGetterCxxMethod =
5213
+ SwiftDeclSynthesizer (
5214
+ static_cast <ClangImporter *>(ctx.getClangModuleLoader ()))
5215
+ .synthesizeCXXForwardingMethod (
5216
+ cast<clang::CXXRecordDecl>(derivedStruct->getClangDecl ()),
5217
+ cast<clang::CXXRecordDecl>(baseStruct->getClangDecl ()), md,
5218
+ ForwardingMethodKind::Base,
5219
+ getterDecl->getResultInterfaceType ()->isForeignReferenceType ()
5220
+ ? ReferenceReturnTypeBehaviorForBaseMethodSynthesis::
5221
+ RemoveReferenceIfPointer
5222
+ : (kind != AccessorKind::Get
5223
+ ? ReferenceReturnTypeBehaviorForBaseMethodSynthesis::
5224
+ KeepReference
5225
+ : ReferenceReturnTypeBehaviorForBaseMethodSynthesis::
5226
+ RemoveReference),
5227
+ /* forceConstQualifier=*/ kind != AccessorKind::MutableAddress);
5404
5228
} else if (auto *fd = dyn_cast_or_null<clang::FieldDecl>(baseClangDecl)) {
5405
5229
ValueDecl *retainOperationFn = nullptr ;
5406
5230
// Check if this field getter is returning a retainable FRT.
@@ -6881,7 +6705,7 @@ static ValueDecl *addThunkForDependentTypes(FuncDecl *oldDecl,
6881
6705
// are not used in the function signature. We supply the type params as explicit
6882
6706
// metatype arguments to aid in typechecking, but they shouldn't be forwarded to
6883
6707
// the corresponding C++ function.
6884
- std::pair<BraceStmt *, bool >
6708
+ static std::pair<BraceStmt *, bool >
6885
6709
synthesizeForwardingThunkBody (AbstractFunctionDecl *afd, void *context) {
6886
6710
ASTContext &ctx = afd->getASTContext ();
6887
6711
0 commit comments