Skip to content

Commit b62d82c

Browse files
committed
Property return extern "C" things through 'members_of'.
Closes issue llvm#82.
1 parent f26b7a0 commit b62d82c

File tree

2 files changed

+76
-8
lines changed

2 files changed

+76
-8
lines changed

clang/lib/Sema/Metafunctions.cpp

+34-8
Original file line numberDiff line numberDiff line change
@@ -1071,24 +1071,37 @@ static bool ensureDeclared(Sema &S, QualType QT, SourceLocation SpecLoc) {
10711071

10721072
static bool isReflectableDecl(ASTContext &C, const Decl *D) {
10731073
assert(D && "null declaration");
1074-
if (isa<AccessSpecDecl>(D) || isa<EmptyDecl>(D) || isa<FriendDecl>(D))
1075-
return false;
1074+
10761075
if (isa<NamespaceAliasDecl>(D))
10771076
return true;
1077+
1078+
if (!isa<VarDecl, FunctionDecl, TypeDecl, FieldDecl, TemplateDecl,
1079+
NamespaceDecl, NamespaceAliasDecl, TranslationUnitDecl>(D))
1080+
return false;
1081+
10781082
if (auto *Class = dyn_cast<CXXRecordDecl>(D))
10791083
if (Class->isInjectedClassName())
10801084
return false;
1081-
if (isa<StaticAssertDecl>(D))
1082-
return false;
10831085

10841086
return D->getCanonicalDecl() == D;
10851087
}
10861088

10871089
/// Filter non-reflectable members.
10881090
static Decl *findIterableMember(ASTContext &C, Decl *D, bool Inclusive) {
1089-
if (!D || (Inclusive && isReflectableDecl(C, D)))
1091+
if (!D)
10901092
return D;
10911093

1094+
if (Inclusive) {
1095+
if (isReflectableDecl(C, D))
1096+
return D;
1097+
1098+
// Handle the case where the first Decl is a LinkageSpecDecl.
1099+
if (auto *LSDecl = dyn_cast_or_null<LinkageSpecDecl>(D)) {
1100+
Decl *RecD = findIterableMember(C, *LSDecl->decls_begin(), true);
1101+
if (RecD) return RecD;
1102+
}
1103+
}
1104+
10921105
do {
10931106
DeclContext *DC = D->getDeclContext();
10941107

@@ -1100,17 +1113,30 @@ static Decl *findIterableMember(ASTContext &C, Decl *D, bool Inclusive) {
11001113
// declarations whose DeclContext is different from the previous Decl;
11011114
// otherwise, we may inadvertently break the chain of redeclarations in
11021115
// difficult to predit ways.
1103-
D = D->getNextDeclInContext();
1104-
while (D && D->getDeclContext() != DC)
1105-
D = D->getNextDeclInContext();
1116+
do {
1117+
D = D->getNextDeclInContext();
1118+
} while (D && D->getDeclContext() != DC);
11061119

1120+
// In the case of namespaces, walk the redeclaration chain.
11071121
if (auto *NSDecl = dyn_cast<NamespaceDecl>(DC)) {
11081122
while (!D && NSDecl) {
11091123
NSDecl = NSDecl->getPreviousDecl();
11101124
D = NSDecl ? *NSDecl->decls_begin() : nullptr;
11111125
}
11121126
}
1127+
1128+
// We need to recursively descend into LinkageSpecDecls to iterate over the
1129+
// members declared therein (e.g., `extern "C"` blocks).
1130+
if (auto *LSDecl = dyn_cast_or_null<LinkageSpecDecl>(D)) {
1131+
Decl *RecD = findIterableMember(C, *LSDecl->decls_begin(), true);
1132+
if (RecD) return RecD;
1133+
}
1134+
1135+
// Pop back out of a recursively entered LinkageSpecDecl.
1136+
if (!D && isa<LinkageSpecDecl>(DC))
1137+
return findIterableMember(C, cast<Decl>(DC), false);
11131138
} while (D && !isReflectableDecl(C, D));
1139+
11141140
return D;
11151141
}
11161142

libcxx/test/std/experimental/reflection/members-and-subobjects.pass.cpp

+42
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,48 @@ static_assert((members_of(^myns) | std::views::filter(std::meta::is_template) |
179179
std::vector{^myns::TAlias});
180180
} // namespace_members
181181

182+
// ===========================
183+
// language_linkage_specifiers
184+
// ===========================
185+
186+
namespace language_linkage_specifiers {
187+
namespace with_empty {
188+
extern "C" { }
189+
} // namespace with_empty
190+
191+
namespace leading_node {
192+
extern "C" {
193+
void fn1();
194+
} // extern "C"
195+
196+
void fn2();
197+
} // namespace leading_node
198+
199+
namespace multiple_blocks {
200+
extern "C" {
201+
void fn3();
202+
} // extern "C"
203+
204+
void fn4();
205+
206+
extern "C" {
207+
void fn5();
208+
} // extern "C"
209+
} // namespace multiple_blocks
210+
211+
namespace multiple_blocks {
212+
void fn6();
213+
214+
extern "C" {
215+
void fn7();
216+
}
217+
} // namespace multiple_blocks
218+
219+
static_assert(members_of(^with_empty).size() == 0);
220+
static_assert(members_of(^leading_node).size() == 2);
221+
static_assert(members_of(^multiple_blocks).size() == 5);
222+
} // namespace language_linkage_specifiers
223+
182224
// ==========================
183225
// inaccessible_class_members
184226
// ==========================

0 commit comments

Comments
 (0)