Skip to content

Commit fc2dc6a

Browse files
committed
C++ Interop: improve skipping already imported struct members
This fixes the issue that prevents `std::string::size_type` from being imported into Swift: `size_type` is imported before its parent struct, and we're skipping it when importing the struct afterwards. This is caused by an out-of-line decl for `std::string::npos`: ```cpp template<class _CharT, class _Traits, class _Allocator> _LIBCPP_FUNC_VIS const typename basic_string<_CharT, _Traits, _Allocator>::size_type basic_string<_CharT, _Traits, _Allocator>::npos; ``` When importing `npos`, we first import `size_type`, which triggers the issue.
1 parent b60c826 commit fc2dc6a

File tree

4 files changed

+61
-6
lines changed

4 files changed

+61
-6
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3501,6 +3501,10 @@ namespace {
35013501
SmallVector<ConstructorDecl *, 4> ctors;
35023502
SmallVector<TypeDecl *, 4> nestedTypes;
35033503

3504+
// Store the already imported members in a set to avoid importing the same
3505+
// decls multiple times.
3506+
SmallPtrSet<clang::Decl *, 16> importedMembers;
3507+
35043508
// FIXME: Import anonymous union fields and support field access when
35053509
// it is nested in a struct.
35063510

@@ -3519,6 +3523,12 @@ namespace {
35193523
}
35203524
}
35213525

3526+
// If we've already imported this decl & added it to the resulting
3527+
// struct, skip it so we don't add the same member twice.
3528+
if (!importedMembers.insert(m->getCanonicalDecl()).second) {
3529+
continue;
3530+
}
3531+
35223532
auto nd = dyn_cast<clang::NamedDecl>(m);
35233533
if (!nd) {
35243534
// We couldn't import the member, so we can't reference it in Swift.
@@ -3547,12 +3557,6 @@ namespace {
35473557
}
35483558
}
35493559

3550-
// If we've already imported this decl, skip it so we don't add the same
3551-
// member twice.
3552-
if (Impl.ImportedDecls.find({nd->getCanonicalDecl(), getVersion()}) !=
3553-
Impl.ImportedDecls.end())
3554-
continue;
3555-
35563560
// If we encounter an IndirectFieldDecl, ensure that its parent is
35573561
// importable before attempting to import it because they are dependent
35583562
// when it comes to getter/setter generation.

test/Interop/Cxx/namespace/Inputs/module.modulemap

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,8 @@ module TemplatesSecondHeader {
3232
header "templates-second-header.h"
3333
requires cplusplus
3434
}
35+
36+
module TemplatesWithForwardDecl {
37+
header "templates-with-forward-decl.h"
38+
requires cplusplus
39+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#ifndef TEST_INTEROP_CXX_NAMESPACE_INPUTS_TEMPLATES_WITH_FORWARD_DECL_H
2+
#define TEST_INTEROP_CXX_NAMESPACE_INPUTS_TEMPLATES_WITH_FORWARD_DECL_H
3+
4+
namespace NS1 {
5+
6+
template <typename T>
7+
struct Decl;
8+
9+
typedef Decl<int> di;
10+
11+
} // namespace NS1
12+
13+
namespace NS1 {
14+
15+
template <typename T>
16+
struct ForwardDeclared;
17+
18+
template <typename T>
19+
struct Decl {
20+
typedef T MyInt;
21+
ForwardDeclared<T> fwd;
22+
const static MyInt intValue = -1;
23+
};
24+
25+
template <typename T>
26+
const typename Decl<T>::MyInt Decl<T>::intValue;
27+
28+
} // namespace NS1
29+
30+
namespace NS1 {
31+
32+
template <typename T>
33+
struct ForwardDeclared {};
34+
35+
} // namespace NS1
36+
37+
#endif // TEST_INTEROP_CXX_NAMESPACE_INPUTS_TEMPLATES_WITH_FORWARD_DECL_H
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: %target-swift-ide-test -print-module -module-to-print=TemplatesWithForwardDecl -I %S/Inputs -source-filename=x -enable-cxx-interop | %FileCheck %s
2+
3+
// CHECK: extension NS1 {
4+
// CHECK: struct __CxxTemplateInstN3NS14DeclIiEE {
5+
// CHECK: typealias MyInt = Int32
6+
// CHECK: var fwd: NS1.__CxxTemplateInstN3NS115ForwardDeclaredIiEE
7+
// CHECK: static let intValue: NS1.__CxxTemplateInstN3NS14DeclIiEE.MyInt
8+
// CHECK: }
9+
// CHECK: }

0 commit comments

Comments
 (0)