@@ -4773,13 +4773,17 @@ static clang::CXXMethodDecl *synthesizeCxxBaseMethod(
4773
4773
auto &clangSema = impl.getClangSema ();
4774
4774
4775
4775
// Create a new method in the derived class that calls the base method.
4776
- auto name = method->getNameInfo ().getName ();
4776
+ clang::DeclarationName name = method->getNameInfo ().getName ();
4777
4777
if (name.isIdentifier ()) {
4778
4778
std::string newName;
4779
4779
llvm::raw_string_ostream os (newName);
4780
4780
os << " __synthesizedBaseCall_" << name.getAsIdentifierInfo ()->getName ();
4781
4781
name = clang::DeclarationName (
4782
4782
&impl.getClangPreprocessor ().getIdentifierTable ().get (os.str ()));
4783
+ } else if (name.getCXXOverloadedOperator () == clang::OO_Subscript) {
4784
+ name = clang::DeclarationName (
4785
+ &impl.getClangPreprocessor ().getIdentifierTable ().get (
4786
+ " __synthesizedBaseCall_operatorSubscript" ));
4783
4787
}
4784
4788
auto newMethod = clang::CXXMethodDecl::Create (
4785
4789
clangCtx, const_cast <clang::CXXRecordDecl *>(derivedClass),
@@ -4966,9 +4970,94 @@ synthesizeBaseClassMethodBody(AbstractFunctionDecl *afd, void *context) {
4966
4970
return {body, /* isTypeChecked=*/ true };
4967
4971
}
4968
4972
4969
- // Getters are relatively easy. Just cast and return the member:
4970
- // %0 = __swift_interopStaticCast<Base>(self)
4971
- // return %0.member
4973
+ // Synthesize a C++ method that returns the field of interest from the base
4974
+ // class. This lets Clang take care of the cast from the derived class
4975
+ // to the base class while the field is accessed.
4976
+ static clang::CXXMethodDecl *synthesizeCxxBaseGetterAccessorMethod (
4977
+ ClangImporter &impl, const clang::CXXRecordDecl *derivedClass,
4978
+ const clang::CXXRecordDecl *baseClass, const clang::FieldDecl *field) {
4979
+ auto &clangCtx = impl.getClangASTContext ();
4980
+ auto &clangSema = impl.getClangSema ();
4981
+
4982
+ // Create a new method in the derived class that calls the base method.
4983
+ auto name = field->getDeclName ();
4984
+ if (name.isIdentifier ()) {
4985
+ std::string newName;
4986
+ llvm::raw_string_ostream os (newName);
4987
+ os << " __synthesizedBaseGetterAccessor_"
4988
+ << name.getAsIdentifierInfo ()->getName ();
4989
+ name = clang::DeclarationName (
4990
+ &impl.getClangPreprocessor ().getIdentifierTable ().get (os.str ()));
4991
+ }
4992
+ auto returnType = field->getType ();
4993
+ if (returnType->isReferenceType ())
4994
+ returnType = returnType->getPointeeType ();
4995
+ clang::FunctionProtoType::ExtProtoInfo info;
4996
+ info.TypeQuals .addConst ();
4997
+ info.ExceptionSpec .Type = clang::EST_NoThrow;
4998
+ auto ftype = clangCtx.getFunctionType (returnType, {}, info);
4999
+ auto newMethod = clang::CXXMethodDecl::Create (
5000
+ clangCtx, const_cast <clang::CXXRecordDecl *>(derivedClass),
5001
+ field->getSourceRange ().getBegin (),
5002
+ clang::DeclarationNameInfo (name, clang::SourceLocation ()), ftype,
5003
+ clangCtx.getTrivialTypeSourceInfo (ftype), clang::SC_None,
5004
+ /* UsesFPIntrin=*/ false , /* isInline=*/ true ,
5005
+ clang::ConstexprSpecKind::Unspecified, field->getSourceRange ().getEnd ());
5006
+ newMethod->setImplicit ();
5007
+ newMethod->setImplicitlyInline ();
5008
+ newMethod->setAccess (clang::AccessSpecifier::AS_public);
5009
+
5010
+ // Create a new Clang diagnostic pool to capture any diagnostics
5011
+ // emitted during the construction of the method.
5012
+ clang::sema::DelayedDiagnosticPool diagPool{
5013
+ clangSema.DelayedDiagnostics .getCurrentPool ()};
5014
+ auto diagState = clangSema.DelayedDiagnostics .push (diagPool);
5015
+
5016
+ // Construct the method's body.
5017
+ auto *thisExpr = new (clangCtx) clang::CXXThisExpr (
5018
+ clang::SourceLocation (), newMethod->getThisType (), /* IsImplicit=*/ false );
5019
+ clang::QualType baseClassPtr = clangCtx.getRecordType (baseClass);
5020
+ baseClassPtr.addConst ();
5021
+ baseClassPtr = clangCtx.getPointerType (baseClassPtr);
5022
+
5023
+ clang::CastKind Kind;
5024
+ clang::CXXCastPath Path;
5025
+ clangSema.CheckPointerConversion (thisExpr, baseClassPtr, Kind, Path,
5026
+ /* IgnoreBaseAccess=*/ false ,
5027
+ /* Diagnose=*/ true );
5028
+ auto conv = clangSema.ImpCastExprToType (thisExpr, baseClassPtr, Kind,
5029
+ clang::VK_PRValue, &Path);
5030
+ if (!conv.isUsable ())
5031
+ return nullptr ;
5032
+ auto memberExpr = clangSema.BuildMemberExpr (
5033
+ conv.get (), /* isArrow=*/ true , clang::SourceLocation (),
5034
+ clang::NestedNameSpecifierLoc (), clang::SourceLocation (),
5035
+ const_cast <clang::FieldDecl *>(field),
5036
+ clang::DeclAccessPair::make (const_cast <clang::FieldDecl *>(field),
5037
+ clang::AS_public),
5038
+ /* HadMultipleCandidates=*/ false ,
5039
+ clang::DeclarationNameInfo (field->getDeclName (), clang::SourceLocation ()),
5040
+ returnType, clang::VK_LValue, clang::OK_Ordinary);
5041
+ auto returnCast = clangSema.ImpCastExprToType (
5042
+ memberExpr, returnType, clang::CK_LValueToRValue, clang::VK_PRValue);
5043
+ if (!returnCast.isUsable ())
5044
+ return nullptr ;
5045
+ auto returnStmt = clang::ReturnStmt::Create (clangCtx, clang::SourceLocation (),
5046
+ returnCast.get (), nullptr );
5047
+
5048
+ // Check if there were any Clang errors during the construction
5049
+ // of the method body.
5050
+ clangSema.DelayedDiagnostics .popWithoutEmitting (diagState);
5051
+ if (!diagPool.empty ())
5052
+ return nullptr ;
5053
+ newMethod->setBody (returnStmt);
5054
+ return newMethod;
5055
+ }
5056
+
5057
+ // Generates the body of a derived method, that invokes the base
5058
+ // field getter or the base subscript.
5059
+ // The method's body takes the following form:
5060
+ // return self.__synthesizedBaseCall_fn(args...)
4972
5061
static std::pair<BraceStmt *, bool >
4973
5062
synthesizeBaseClassFieldGetterBody (AbstractFunctionDecl *afd, void *context) {
4974
5063
ASTContext &ctx = afd->getASTContext ();
@@ -4980,48 +5069,78 @@ synthesizeBaseClassFieldGetterBody(AbstractFunctionDecl *afd, void *context) {
4980
5069
NominalTypeDecl *derivedStruct =
4981
5070
cast<NominalTypeDecl>(getterDecl->getDeclContext ()->getAsDecl ());
4982
5071
5072
+ const clang::Decl *baseClangDecl;
5073
+ if (baseClassVar->getClangDecl ())
5074
+ baseClangDecl = baseClassVar->getClangDecl ();
5075
+ else
5076
+ baseClangDecl =
5077
+ getCalledBaseCxxMethod (baseClassVar->getAccessor (AccessorKind::Get));
5078
+
5079
+ clang::CXXMethodDecl *baseGetterCxxMethod = nullptr ;
5080
+ if (auto *md = dyn_cast_or_null<clang::CXXMethodDecl>(baseClangDecl)) {
5081
+ // Subscript operator is represented through a generated
5082
+ // C++ method call that calls the base operator.
5083
+ baseGetterCxxMethod = synthesizeCxxBaseMethod (
5084
+ *static_cast <ClangImporter *>(ctx.getClangModuleLoader ()),
5085
+ cast<clang::CXXRecordDecl>(derivedStruct->getClangDecl ()),
5086
+ cast<clang::CXXRecordDecl>(baseStruct->getClangDecl ()), md);
5087
+ } else if (auto *fd = dyn_cast_or_null<clang::FieldDecl>(baseClangDecl)) {
5088
+ // Field getter is represented through a generated
5089
+ // C++ method call that returns the value of the base field.
5090
+ baseGetterCxxMethod = synthesizeCxxBaseGetterAccessorMethod (
5091
+ *static_cast <ClangImporter *>(ctx.getClangModuleLoader ()),
5092
+ cast<clang::CXXRecordDecl>(derivedStruct->getClangDecl ()),
5093
+ cast<clang::CXXRecordDecl>(baseStruct->getClangDecl ()), fd);
5094
+ }
5095
+
5096
+ if (!baseGetterCxxMethod) {
5097
+ ctx.Diags .diagnose (SourceLoc (), diag::failed_base_method_call_synthesis,
5098
+ getterDecl, baseStruct);
5099
+ auto body = BraceStmt::create (ctx, SourceLoc (), {}, SourceLoc (),
5100
+ /* implicit=*/ true );
5101
+ return {body, true };
5102
+ }
5103
+ auto *baseGetterMethod = cast<FuncDecl>(
5104
+ ctx.getClangModuleLoader ()->importDeclDirectly (baseGetterCxxMethod));
5105
+
4983
5106
auto selfDecl = getterDecl->getImplicitSelfDecl ();
4984
5107
auto selfExpr = new (ctx) DeclRefExpr (selfDecl, DeclNameLoc (),
4985
5108
/* implicit*/ true );
4986
5109
selfExpr->setType (selfDecl->getTypeInContext ());
4987
5110
4988
- auto staticCastRefExpr = getInteropStaticCastDeclRefExpr (
4989
- ctx, baseStruct->getClangDecl ()->getOwningModule (),
4990
- baseStruct->getSelfInterfaceType (),
4991
- derivedStruct->getSelfInterfaceType ());
5111
+ Argument selfArg = Argument::unlabeled (selfExpr);
4992
5112
4993
- auto *argList = ArgumentList::forImplicitUnlabeled (ctx, {selfExpr});
4994
- auto casted = CallExpr::createImplicit (ctx, staticCastRefExpr, argList);
4995
- casted->setType (baseStruct->getSelfInterfaceType ());
4996
- casted->setThrows (false );
5113
+ auto *baseMemberExpr =
5114
+ new (ctx) DeclRefExpr (ConcreteDeclRef (baseGetterMethod), DeclNameLoc (),
5115
+ /* Implicit=*/ true );
5116
+ baseMemberExpr->setType (baseGetterMethod->getInterfaceType ());
5117
+
5118
+ auto baseMemberDotCallExpr =
5119
+ DotSyntaxCallExpr::create (ctx, baseMemberExpr, SourceLoc (), selfArg);
5120
+ baseMemberDotCallExpr->setType (baseGetterMethod->getMethodInterfaceType ());
5121
+ baseMemberDotCallExpr->setThrows (false );
4997
5122
4998
- Expr *baseMember = nullptr ;
5123
+ ArgumentList *argumentList ;
4999
5124
if (auto subscript = dyn_cast<SubscriptDecl>(baseClassVar)) {
5000
5125
auto paramDecl = getterDecl->getParameters ()->get (0 );
5001
- auto paramRefExpr = new (ctx) DeclRefExpr (paramDecl,
5002
- DeclNameLoc (),
5003
- /* Implicit=*/ true );
5126
+ auto paramRefExpr = new (ctx) DeclRefExpr (paramDecl, DeclNameLoc (),
5127
+ /* Implicit=*/ true );
5004
5128
paramRefExpr->setType (paramDecl->getTypeInContext ());
5005
-
5006
- auto *argList = ArgumentList::forImplicitUnlabeled (ctx, {paramRefExpr});
5007
- baseMember = SubscriptExpr::create (ctx, casted, argList, subscript);
5008
- baseMember->setType (subscript->getElementInterfaceType ());
5129
+ argumentList = ArgumentList::forImplicitUnlabeled (ctx, {paramRefExpr});
5009
5130
} else {
5010
- // If the base class var has a clang decl, that means it's an access into a
5011
- // stored field. Otherwise, we're looking into another base class, so it's a
5012
- // another synthesized accessor.
5013
- AccessSemantics accessKind = baseClassVar->getClangDecl ()
5014
- ? AccessSemantics::DirectToStorage
5015
- : AccessSemantics::DirectToImplementation;
5016
- baseMember =
5017
- new (ctx) MemberRefExpr (casted, SourceLoc (), baseClassVar, DeclNameLoc (),
5018
- /* Implicit=*/ true , accessKind);
5019
- baseMember->setType (cast<VarDecl>(baseClassVar)->getTypeInContext ());
5131
+ argumentList = ArgumentList::forImplicitUnlabeled (ctx, {});
5020
5132
}
5021
5133
5022
- auto ret = new (ctx) ReturnStmt (SourceLoc (), baseMember);
5023
- auto body = BraceStmt::create (ctx, SourceLoc (), {ret}, SourceLoc (),
5024
- /* implicit*/ true );
5134
+ auto *baseMemberCallExpr =
5135
+ CallExpr::createImplicit (ctx, baseMemberDotCallExpr, argumentList);
5136
+ baseMemberCallExpr->setType (baseGetterMethod->getResultInterfaceType ());
5137
+ baseMemberCallExpr->setThrows (false );
5138
+
5139
+ auto returnStmt = new (ctx) ReturnStmt (SourceLoc (), baseMemberCallExpr,
5140
+ /* implicit=*/ true );
5141
+
5142
+ auto body = BraceStmt::create (ctx, SourceLoc (), {returnStmt}, SourceLoc (),
5143
+ /* implicit=*/ true );
5025
5144
return {body, /* isTypeChecked=*/ true };
5026
5145
}
5027
5146
0 commit comments