Skip to content

Commit b4075fc

Browse files
authored
[cxx-interop] Refactor importFunctionDecl() (#85475)
This patch re-arranges the implementation of importFunctionDecl() to delay side-effectful logic as late as possible, to avoid importing or allocating parts of the AST that we do not need.
1 parent 4c977c6 commit b4075fc

File tree

1 file changed

+110
-102
lines changed

1 file changed

+110
-102
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 110 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -3755,9 +3755,35 @@ namespace {
37553755
std::optional<ImportedName> correctSwiftName,
37563756
std::optional<AccessorInfo> accessorInfo,
37573757
const clang::FunctionTemplateDecl *funcTemplate = nullptr) {
3758+
37583759
if (decl->isDeleted())
37593760
return nullptr;
37603761

3762+
// For now, we don't support non-subscript operators which are templated
3763+
bool isOperator = decl->getDeclName().getNameKind() ==
3764+
clang::DeclarationName::CXXOperatorName;
3765+
bool isNonSubscriptOperator =
3766+
isOperator && (decl->getDeclName().getCXXOverloadedOperator() !=
3767+
clang::OO_Subscript);
3768+
if (isNonSubscriptOperator && decl->isTemplated())
3769+
return nullptr;
3770+
3771+
if (auto *ctordecl = dyn_cast<clang::CXXConstructorDecl>(decl)) {
3772+
// Don't import copy constructor or move constructor -- these will be
3773+
// provided through the value witness table.
3774+
if (ctordecl->isCopyConstructor() || ctordecl->isMoveConstructor())
3775+
return nullptr;
3776+
3777+
// Don't import the generic ctors of std::span, rely on the ctors that
3778+
// we instantiate when conforming to the overlay. These generic ctors
3779+
// can cause crashes in codegen.
3780+
// FIXME: figure out why.
3781+
const auto *parent = ctordecl->getParent();
3782+
if (funcTemplate && parent->isInStdNamespace() &&
3783+
parent->getIdentifier() && parent->getName() == "span")
3784+
return nullptr;
3785+
}
3786+
37613787
if (Impl.SwiftContext.LangOpts.EnableCXXInterop &&
37623788
!isa<clang::CXXMethodDecl>(decl)) {
37633789
// Do not import math functions from the C++ standard library, as
@@ -3796,56 +3822,10 @@ namespace {
37963822
}
37973823
}
37983824

3799-
auto dc =
3800-
Impl.importDeclContextOf(decl, importedName.getEffectiveContext());
3801-
if (!dc)
3802-
return nullptr;
3803-
3804-
// We may have already imported this function decl before we imported the
3805-
// parent record. In such a case it's important we don't re-import.
3806-
auto known = Impl.ImportedDecls.find({decl, getVersion()});
3807-
if (known != Impl.ImportedDecls.end()) {
3808-
return known->second;
3809-
}
3810-
3811-
bool isOperator = decl->getDeclName().getNameKind() ==
3812-
clang::DeclarationName::CXXOperatorName;
3813-
bool isNonSubscriptOperator =
3814-
isOperator && (decl->getDeclName().getCXXOverloadedOperator() !=
3815-
clang::OO_Subscript);
3816-
3817-
// For now, we don't support non-subscript operators which are templated
3818-
if (isNonSubscriptOperator && decl->isTemplated()) {
3819-
return nullptr;
3820-
}
3821-
3822-
DeclName name = accessorInfo ? DeclName() : importedName.getDeclName();
3823-
auto selfIdx = importedName.getSelfIndex();
3824-
3825-
auto templateParamTypeUsedInSignature =
3826-
[decl](clang::TemplateTypeParmDecl *type) -> bool {
3827-
// TODO(https://github.com/apple/swift/issues/56206): We will want to update this to handle dependent types when those are supported.
3828-
if (hasSameUnderlyingType(decl->getReturnType().getTypePtr(), type))
3829-
return true;
3830-
3831-
for (unsigned i : range(0, decl->getNumParams())) {
3832-
if (hasSameUnderlyingType(
3833-
decl->getParamDecl(i)->getType().getTypePtr(), type))
3834-
return true;
3835-
}
3836-
3837-
return false;
3838-
};
3839-
3840-
ImportedType importedType;
3841-
bool selfIsInOut = false;
3842-
ParameterList *bodyParams = nullptr;
3843-
GenericParamList *genericParams = nullptr;
3844-
SmallVector<GenericTypeParamDecl *, 4> templateParams;
3825+
llvm::SmallSet<clang::NamedDecl *, 4> unusedTemplateParams;
38453826
if (funcTemplate) {
3846-
unsigned i = 0;
3847-
for (auto param : *funcTemplate->getTemplateParameters()) {
3848-
auto templateTypeParam = cast<clang::TemplateTypeParmDecl>(param);
3827+
for (auto *param : *funcTemplate->getTemplateParameters()) {
3828+
auto *templateTypeParam = cast<clang::TemplateTypeParmDecl>(param);
38493829
// If the template type parameter isn't used in the signature then we
38503830
// won't be able to deduce what it is when the function template is
38513831
// called in Swift code. This is OK if there's a defaulted type we can
@@ -3856,38 +3836,58 @@ namespace {
38563836
// If the defaulted template type parameter is used in the signature,
38573837
// then still add a generic so that it can be overrieded.
38583838
// TODO(https://github.com/apple/swift/issues/57184): In the future we might want to import two overloads in this case so that the default type could still be used.
3859-
if (templateTypeParam->hasDefaultArgument() &&
3860-
!templateParamTypeUsedInSignature(templateTypeParam)) {
3839+
auto usedInSignature = [&]() -> bool {
3840+
if (hasSameUnderlyingType(decl->getReturnType().getTypePtr(),
3841+
templateTypeParam))
3842+
return true;
3843+
for (unsigned i : range(0, decl->getNumParams())) {
3844+
if (hasSameUnderlyingType(
3845+
decl->getParamDecl(i)->getType().getTypePtr(),
3846+
templateTypeParam))
3847+
return true;
3848+
}
3849+
return false;
3850+
};
3851+
3852+
if (templateTypeParam->hasDefaultArgument() && !usedInSignature()) {
38613853
// We do not yet support instantiation of default values of template
38623854
// parameters when the function template is instantiated, so do not
38633855
// import the function template if the template parameter has
38643856
// dependent default value.
3865-
auto &defaultArgument =
3866-
templateTypeParam->getDefaultArgument().getArgument();
3867-
if (defaultArgument.isDependent())
3857+
if (templateTypeParam->getDefaultArgument()
3858+
.getArgument()
3859+
.isDependent())
38683860
return nullptr;
3869-
continue;
3861+
unusedTemplateParams.insert(param);
38703862
}
3871-
3872-
auto *typeParam = Impl.createDeclWithClangNode<GenericTypeParamDecl>(
3873-
param, AccessLevel::Public, dc,
3874-
Impl.SwiftContext.getIdentifier(param->getName()),
3875-
/*nameLoc*/ Impl.importSourceLoc(param->getLocation()),
3876-
/*specifierLoc*/ SourceLoc(),
3877-
/*depth*/ 0, /*index*/ i, GenericTypeParamKind::Type);
3878-
templateParams.push_back(typeParam);
3879-
(void)++i;
38803863
}
3881-
if (!templateParams.empty())
3882-
genericParams = GenericParamList::create(
3883-
Impl.SwiftContext, SourceLoc(), templateParams, SourceLoc());
3864+
}
3865+
3866+
auto dc =
3867+
Impl.importDeclContextOf(decl, importedName.getEffectiveContext());
3868+
if (!dc)
3869+
return nullptr;
3870+
3871+
// We may have already imported this function decl before we imported the
3872+
// parent record. In such a case it's important we don't re-import.
3873+
auto known = Impl.ImportedDecls.find({decl, getVersion()});
3874+
if (known != Impl.ImportedDecls.end()) {
3875+
return known->second;
3876+
}
3877+
3878+
DeclName name = accessorInfo ? DeclName() : importedName.getDeclName();
3879+
auto selfIdx = importedName.getSelfIndex();
3880+
3881+
if (auto *method = dyn_cast<clang::CXXMethodDecl>(decl);
3882+
method && method->isStatic() && name.getBaseName().isConstructor()) {
3883+
return importGlobalAsInitializer(
3884+
decl, name, dc, importedName.getInitKind(), correctSwiftName);
38843885
}
38853886

38863887
if (!dc->isModuleScopeContext() && !isClangNamespace(dc) &&
38873888
!isa<clang::CXXMethodDecl>(decl)) {
3888-
// Handle initializers.
38893889
if (name.getBaseName().isConstructor()) {
3890-
assert(!accessorInfo);
3890+
ASSERT(!accessorInfo && "accessor should not be constructor()");
38913891
return importGlobalAsInitializer(decl, name, dc,
38923892
importedName.getInitKind(),
38933893
correctSwiftName);
@@ -3906,6 +3906,36 @@ namespace {
39063906
Impl.diagnose({}, diag::note_while_importing, decl->getName());
39073907
return nullptr;
39083908
}
3909+
}
3910+
3911+
SmallVector<GenericTypeParamDecl *, 4> templateParams;
3912+
if (funcTemplate) {
3913+
unsigned i = 0;
3914+
for (auto *param : *funcTemplate->getTemplateParameters()) {
3915+
if (unusedTemplateParams.contains(param))
3916+
continue;
3917+
auto *typeParam = Impl.createDeclWithClangNode<GenericTypeParamDecl>(
3918+
param, AccessLevel::Public, dc,
3919+
Impl.SwiftContext.getIdentifier(param->getName()),
3920+
/*nameLoc*/ Impl.importSourceLoc(param->getLocation()),
3921+
/*specifierLoc*/ SourceLoc(),
3922+
/*depth*/ 0, /*index*/ i, GenericTypeParamKind::Type);
3923+
templateParams.push_back(typeParam);
3924+
(void)++i;
3925+
}
3926+
}
3927+
auto getGenericParams = [&]() -> GenericParamList * {
3928+
if (templateParams.empty())
3929+
return nullptr;
3930+
return GenericParamList::create(Impl.SwiftContext, SourceLoc(),
3931+
templateParams, SourceLoc());
3932+
};
3933+
3934+
ImportedType resultType;
3935+
bool selfIsInOut = false;
3936+
ParameterList *bodyParams = nullptr;
3937+
if (!dc->isModuleScopeContext() && !isClangNamespace(dc) &&
3938+
!isa<clang::CXXMethodDecl>(decl)) {
39093939

39103940
// There is an inout 'self' when the parameter is a pointer to a
39113941
// non-const instance of the type we're importing onto. Importing this
@@ -3946,12 +3976,12 @@ namespace {
39463976
return nullptr;
39473977

39483978
if (decl->getReturnType()->isScalarType())
3949-
importedType =
3979+
resultType =
39503980
Impl.importFunctionReturnType(dc, decl, allowNSUIntegerAsInt);
39513981
} else {
39523982
// Import the function type. If we have parameters, make sure their
39533983
// names get into the resulting function type.
3954-
importedType = Impl.importFunctionParamsAndReturnType(
3984+
resultType = Impl.importFunctionParamsAndReturnType(
39553985
dc, decl, {decl->param_begin(), decl->param_size()},
39563986
decl->isVariadic(), isInSystemModule(dc), name, bodyParams,
39573987
templateParams);
@@ -3992,35 +4022,15 @@ namespace {
39924022
}
39934023

39944024
auto loc = Impl.importSourceLoc(decl->getLocation());
4025+
// FIXME: Poor location info.
4026+
auto nameLoc = Impl.importSourceLoc(decl->getLocation());
39954027

39964028
ClangNode clangNode = decl;
39974029
if (funcTemplate)
39984030
clangNode = funcTemplate;
39994031

4000-
// FIXME: Poor location info.
4001-
auto nameLoc = Impl.importSourceLoc(decl->getLocation());
4002-
4003-
if (auto method = dyn_cast<clang::CXXMethodDecl>(decl);
4004-
method && method->isStatic() && name.getBaseName().isConstructor()) {
4005-
return importGlobalAsInitializer(
4006-
decl, name, dc, importedName.getInitKind(), correctSwiftName);
4007-
}
40084032
AbstractFunctionDecl *result = nullptr;
40094033
if (auto *ctordecl = dyn_cast<clang::CXXConstructorDecl>(decl)) {
4010-
// Don't import copy constructor or move constructor -- these will be
4011-
// provided through the value witness table.
4012-
if (ctordecl->isCopyConstructor() || ctordecl->isMoveConstructor())
4013-
return nullptr;
4014-
4015-
// Don't import the generic ctors of std::span, rely on the ctors that
4016-
// we instantiate when conforming to the overlay. These generic ctors
4017-
// can cause crashes in codegen.
4018-
// FIXME: figure out why.
4019-
const auto *parent = ctordecl->getParent();
4020-
if (funcTemplate && parent->isInStdNamespace() &&
4021-
parent->getIdentifier() && parent->getName() == "span")
4022-
return nullptr;
4023-
40244034
DeclName ctorName(Impl.SwiftContext, DeclBaseName::createConstructor(),
40254035
bodyParams);
40264036
result = Impl.createDeclWithClangNode<ConstructorDecl>(
@@ -4029,20 +4039,18 @@ namespace {
40294039
/*failable=*/false, /*FailabilityLoc=*/SourceLoc(),
40304040
/*Async=*/false, /*AsyncLoc=*/SourceLoc(),
40314041
/*Throws=*/false, /*ThrowsLoc=*/SourceLoc(),
4032-
/*ThrownType=*/TypeLoc(), bodyParams, genericParams, dc);
4042+
/*ThrownType=*/TypeLoc(), bodyParams, getGenericParams(), dc);
40334043
} else {
4034-
auto resultTy = importedType.getType();
4035-
4036-
FuncDecl *func = createFuncOrAccessor(
4037-
Impl, loc, accessorInfo, name, nameLoc, genericParams, bodyParams,
4038-
resultTy,
4044+
auto *func = createFuncOrAccessor(
4045+
Impl, loc, accessorInfo, name, nameLoc, getGenericParams(),
4046+
bodyParams, resultType.getType(),
40394047
/*async=*/false, /*throws=*/false, dc, clangNode);
40404048
result = func;
40414049

40424050
if (!dc->isModuleScopeContext()) {
4043-
if (selfIsInOut)
4051+
if (selfIsInOut) {
40444052
func->setSelfAccessKind(SelfAccessKind::Mutating);
4045-
else {
4053+
} else {
40464054
if (getImplicitObjectParamAnnotation<clang::LifetimeBoundAttr>(
40474055
decl))
40484056
func->setSelfAccessKind(SelfAccessKind::Borrowing);
@@ -4075,7 +4083,7 @@ namespace {
40754083
result->setIsDynamic(false);
40764084

40774085
Impl.recordImplicitUnwrapForDecl(result,
4078-
importedType.isImplicitlyUnwrapped());
4086+
resultType.isImplicitlyUnwrapped());
40794087

40804088
if (dc->getSelfClassDecl())
40814089
// FIXME: only if the class itself is not marked final

0 commit comments

Comments
 (0)