Skip to content

Commit 638abd9

Browse files
committed
[cxx-interop] Refactor: move synthesis logic elsewhere
1 parent 3e75fd2 commit 638abd9

File tree

4 files changed

+211
-188
lines changed

4 files changed

+211
-188
lines changed

include/swift/ClangImporter/ClangImporter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ typedef llvm::PointerUnion<const clang::Decl *, const clang::MacroInfo *,
131131
/// from Clang ASTs over to Swift ASTs.
132132
class ClangImporter final : public ClangModuleLoader {
133133
friend class ClangModuleUnit;
134+
friend class SwiftDeclSynthesizer;
134135

135136
// Make requests in the ClangImporter zone friends so they can access `Impl`.
136137
#define SWIFT_REQUEST(Zone, Name, Sig, Caching, LocOptions) \

lib/ClangImporter/ClangImporter.cpp

Lines changed: 21 additions & 187 deletions
Original file line numberDiff line numberDiff line change
@@ -4891,177 +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 &param = *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-
50654894
// Find the base C++ method called by the base function we want to synthesize
50664895
// the derived thunk for.
50674896
// The base C++ method is either the original C++ method that corresponds
@@ -5117,9 +4946,11 @@ FuncDecl *synthesizeBaseFunctionDeclCall(ClangImporter &impl, ASTContext &ctx,
51174946
auto *cxxMethod = getCalledBaseCxxMethod(baseMember);
51184947
if (!cxxMethod)
51194948
return nullptr;
5120-
auto *newClangMethod = synthesizeCxxBaseMethod(
5121-
impl, cast<clang::CXXRecordDecl>(derivedStruct->getClangDecl()),
5122-
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);
51234954
if (!newClangMethod)
51244955
return nullptr;
51254956
return cast_or_null<FuncDecl>(
@@ -5378,19 +5209,22 @@ synthesizeBaseClassFieldGetterOrAddressGetterBody(AbstractFunctionDecl *afd,
53785209
if (auto *md = dyn_cast_or_null<clang::CXXMethodDecl>(baseClangDecl)) {
53795210
// Subscript operator, or `.pointee` wrapper is represented through a
53805211
// generated C++ method call that calls the base operator.
5381-
baseGetterCxxMethod = synthesizeCxxBaseMethod(
5382-
*static_cast<ClangImporter *>(ctx.getClangModuleLoader()),
5383-
cast<clang::CXXRecordDecl>(derivedStruct->getClangDecl()),
5384-
cast<clang::CXXRecordDecl>(baseStruct->getClangDecl()), md,
5385-
getterDecl->getResultInterfaceType()->isForeignReferenceType()
5386-
? ReferenceReturnTypeBehaviorForBaseMethodSynthesis::
5387-
RemoveReferenceIfPointer
5388-
: (kind != AccessorKind::Get
5389-
? ReferenceReturnTypeBehaviorForBaseMethodSynthesis::
5390-
KeepReference
5391-
: ReferenceReturnTypeBehaviorForBaseMethodSynthesis::
5392-
RemoveReference),
5393-
/*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);
53945228
} else if (auto *fd = dyn_cast_or_null<clang::FieldDecl>(baseClangDecl)) {
53955229
ValueDecl *retainOperationFn = nullptr;
53965230
// Check if this field getter is returning a retainable FRT.

0 commit comments

Comments
 (0)