Skip to content

Commit 916540d

Browse files
committed
export private static fields of classes with friends
1 parent d733d4e commit 916540d

2 files changed

Lines changed: 34 additions & 3 deletions

File tree

Sources/idt/idt.cc

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ apply_fixits("apply-fixits", llvm::cl::init(false),
5151
llvm::cl::desc("Apply suggested changes to decorate interfaces"),
5252
llvm::cl::cat(idt::category));
5353

54+
llvm::cl::opt<bool>
55+
friendly_fields("friendly-fields", llvm::cl::init(false),
56+
llvm::cl::desc("Export private fields of classes with friends"),
57+
llvm::cl::cat(idt::category));
58+
5459
llvm::cl::opt<bool>
5560
inplace("inplace", llvm::cl::init(false),
5661
llvm::cl::desc("Apply suggested changes in-place"),
@@ -291,6 +296,16 @@ class visitor : public clang::RecursiveASTVisitor<visitor> {
291296
return false;
292297
}
293298

299+
template <typename Decl_>
300+
bool parent_record_has_friends(const Decl_ *D) const {
301+
if (auto *ParentRecord = llvm::dyn_cast<clang::CXXRecordDecl>(D->getDeclContext()))
302+
for (auto *PD : ParentRecord->decls())
303+
if (llvm::dyn_cast<clang::FriendDecl>(PD))
304+
return true;
305+
306+
return false;
307+
}
308+
294309
// Determine if a function needs exporting and add the export annotation as
295310
// required.
296311
void export_function_if_needed(const clang::FunctionDecl *FD) {
@@ -549,9 +564,11 @@ class visitor : public clang::RecursiveASTVisitor<visitor> {
549564
// VisitVarDecl will visit all variable declarations as well as static fields
550565
// in classes and structs. Non-static fields are not visited by this method.
551566
bool VisitVarDecl(clang::VarDecl *VD) {
552-
// Ignore private static field declarations. Any that require export will be
553-
// identified by VisitDeclRefExpr.
554-
if (VD->getAccess() == clang::AccessSpecifier::AS_private)
567+
// Ignore private static field declarations unless the class has friends
568+
// that may need access to them. Any other private fields requiring export
569+
// will be identified by VisitDeclRefExpr.
570+
if (VD->getAccess() == clang::AccessSpecifier::AS_private &&
571+
(!friendly_fields || !parent_record_has_friends(VD)))
555572
return true;
556573

557574
export_variable_if_needed(VD);
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// RUN: %idt --friendly-fields --export-macro IDT_TEST_ABI %s 2>&1 | %FileCheck %s
2+
3+
struct KeyType {};
4+
5+
template <typename T> struct FriendTemplate {
6+
static KeyType *getKey() { return &T::Key; }
7+
};
8+
9+
class ClassWithPrivateStaticField : public FriendTemplate<ClassWithPrivateStaticField> {
10+
friend FriendTemplate<ClassWithPrivateStaticField>;
11+
12+
// CHECK: FriendReadsPrivateStaticField.hh:[[@LINE+1]]:3: remark: unexported public interface 'Key'
13+
static KeyType Key;
14+
};

0 commit comments

Comments
 (0)