@@ -4891,187 +4891,6 @@ MemberRefExpr *getSelfInteropStaticCast(FuncDecl *funcDecl,
48914891 return pointeePropertyRefExpr;
48924892}
48934893
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-
50754894// Find the base C++ method called by the base function we want to synthesize
50764895// the derived thunk for.
50774896// The base C++ method is either the original C++ method that corresponds
@@ -5127,9 +4946,11 @@ FuncDecl *synthesizeBaseFunctionDeclCall(ClangImporter &impl, ASTContext &ctx,
51274946 auto *cxxMethod = getCalledBaseCxxMethod (baseMember);
51284947 if (!cxxMethod)
51294948 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);
51334954 if (!newClangMethod)
51344955 return nullptr ;
51354956 return cast_or_null<FuncDecl>(
@@ -5388,19 +5209,22 @@ synthesizeBaseClassFieldGetterOrAddressGetterBody(AbstractFunctionDecl *afd,
53885209 if (auto *md = dyn_cast_or_null<clang::CXXMethodDecl>(baseClangDecl)) {
53895210 // Subscript operator, or `.pointee` wrapper is represented through a
53905211 // 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);
54045228 } else if (auto *fd = dyn_cast_or_null<clang::FieldDecl>(baseClangDecl)) {
54055229 ValueDecl *retainOperationFn = nullptr ;
54065230 // Check if this field getter is returning a retainable FRT.
@@ -6881,7 +6705,7 @@ static ValueDecl *addThunkForDependentTypes(FuncDecl *oldDecl,
68816705// are not used in the function signature. We supply the type params as explicit
68826706// metatype arguments to aid in typechecking, but they shouldn't be forwarded to
68836707// the corresponding C++ function.
6884- std::pair<BraceStmt *, bool >
6708+ static std::pair<BraceStmt *, bool >
68856709synthesizeForwardingThunkBody (AbstractFunctionDecl *afd, void *context) {
68866710 ASTContext &ctx = afd->getASTContext ();
68876711
0 commit comments