Skip to content

Commit 602b996

Browse files
committed
Implement 'offset_of' for base class relationships.
Closes llvm#129.
1 parent 2506603 commit 602b996

File tree

3 files changed

+56
-6
lines changed

3 files changed

+56
-6
lines changed

clang/include/clang/Basic/DiagnosticMetafnKinds.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ def metafn_function_is_not_member_of_object : Note<
7171
def metafn_function_returns_void : Note<
7272
"cannot invoke reflection of void-returning function">;
7373

74+
// Layout.
75+
def metafn_offset_virtual_base_of_abstract : Note<
76+
"cannot query the layout of a virtual base class of an abstract class">;
77+
7478
// Accessibility.
7579
def metafn_access_query_class_being_defined : Note<
7680
"cannot query the access of a member of class %0 currently being defined">;

clang/lib/AST/ExprConstantMeta.cpp

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1265,6 +1265,24 @@ static size_t getBitOffsetOfField(ASTContext &C, const FieldDecl *FD) {
12651265
return Layout.getFieldOffset(FD->getFieldIndex());
12661266
}
12671267

1268+
static size_t getOffsetOfBase(ASTContext &C, const CXXBaseSpecifier *Base) {
1269+
const CXXRecordDecl *Derived = Base->getDerived();
1270+
assert(Derived && "no parent for field!");
1271+
1272+
const ASTRecordLayout &Layout = C.getASTRecordLayout(Derived);
1273+
1274+
QualType BaseQT = Base->getType();
1275+
BaseQT = desugarType(BaseQT, /*UnwrapAliases=*/true, /*DropCV=*/false,
1276+
/*DropRefs=*/false);
1277+
CXXRecordDecl *RD = BaseQT->getAsCXXRecordDecl();
1278+
assert(RD && "base isn't a record type?");
1279+
1280+
if (Base->isVirtual())
1281+
return Layout.getVBaseClassOffset(RD).getQuantity();
1282+
else
1283+
return Layout.getBaseClassOffset(RD).getQuantity();
1284+
}
1285+
12681286
static bool ensureDeclared(ASTContext &C, QualType QT, SourceLocation SpecLoc) {
12691287
// If it's an ElaboratedType, get the underlying NamedType.
12701288
if (const ElaboratedType *ET = dyn_cast<ElaboratedType>(QT))
@@ -4903,7 +4921,6 @@ bool offset_of(APValue &Result, ASTContext &C, MetaActions &Meta,
49034921
case ReflectionKind::Value:
49044922
case ReflectionKind::Template:
49054923
case ReflectionKind::Namespace:
4906-
case ReflectionKind::BaseSpecifier:
49074924
case ReflectionKind::DataMemberSpec:
49084925
case ReflectionKind::Annotation:
49094926
return DiagnoseReflectionKind(Diagnoser, Range, "a non-static data member",
@@ -4916,6 +4933,16 @@ bool offset_of(APValue &Result, ASTContext &C, MetaActions &Meta,
49164933
return DiagnoseReflectionKind(Diagnoser, Range, "a non-static data member",
49174934
DescriptionOf(RV));
49184935
}
4936+
case ReflectionKind::BaseSpecifier: {
4937+
CXXBaseSpecifier *Base = RV.getReflectedBaseSpecifier();
4938+
if (Base->isVirtual() && Base->getDerived()->isAbstract())
4939+
return Diagnoser(Range.getBegin(),
4940+
diag::metafn_offset_virtual_base_of_abstract)
4941+
<< Range;
4942+
4943+
size_t Offset = getOffsetOfBase(C, Base);
4944+
return SetAndSucceed(Result, APValue(C.MakeIntValue(Offset, ResultTy)));
4945+
}
49194946
}
49204947
llvm_unreachable("unknown reflection kind");
49214948
}
@@ -4990,7 +5017,6 @@ bool bit_offset_of(APValue &Result, ASTContext &C, MetaActions &Meta,
49905017
case ReflectionKind::Value:
49915018
case ReflectionKind::Template:
49925019
case ReflectionKind::Namespace:
4993-
case ReflectionKind::BaseSpecifier:
49945020
case ReflectionKind::DataMemberSpec:
49955021
case ReflectionKind::Annotation:
49965022
return DiagnoseReflectionKind(Diagnoser, Range, "a non-static data member",
@@ -5003,6 +5029,8 @@ bool bit_offset_of(APValue &Result, ASTContext &C, MetaActions &Meta,
50035029
return DiagnoseReflectionKind(Diagnoser, Range, "a non-static data member",
50045030
DescriptionOf(RV));
50055031
}
5032+
case ReflectionKind::BaseSpecifier:
5033+
return SetAndSucceed(Result, APValue(C.MakeIntValue(0, ResultTy)));
50065034
}
50075035
llvm_unreachable("unknown reflection kind");
50085036
}

libcxx/test/std/experimental/reflection/layout.pass.cpp

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
//===----------------------------------------------------------------------===//
1010

1111
// UNSUPPORTED: c++03 || c++11 || c++14 || c++17 || c++20
12-
// ADDITIONAL_COMPILE_FLAGS: -freflection
12+
// ADDITIONAL_COMPILE_FLAGS: -freflection -faccess-contexts
1313

1414
// <experimental/reflection>
1515
//
@@ -50,20 +50,20 @@ struct BitField {
5050
};
5151
static_assert(offset_of(^^BitField::bf1) == std::meta::member_offset{0, 0});
5252
static_assert(offset_of(^^BitField::bf2) == std::meta::member_offset{0, 1});
53-
static_assert(offset_of(nonstatic_data_members_of(^^BitField)[2]) ==
53+
static_assert(offset_of(nonstatic_data_members_of(^^BitField, {})[2]) ==
5454
std::meta::member_offset{1, 0});
5555
static_assert(offset_of(^^BitField::bf3) == std::meta::member_offset{1, 0});
5656
static_assert(offset_of(^^BitField::bf4) == std::meta::member_offset{1, 3});
5757
static_assert(bit_size_of(^^BitField::bf1) == 1);
5858
static_assert(bit_size_of(^^BitField::bf2) == 2);
59-
static_assert(bit_size_of((members_of(^^BitField) |
59+
static_assert(bit_size_of((members_of(^^BitField, {}) |
6060
std::views::filter(std::meta::is_bit_field) |
6161
std::ranges::to<std::vector>())[2]) == 0);
6262
static_assert(bit_size_of(^^BitField::bf3) == 3);
6363
static_assert(bit_size_of(^^BitField::bf4) == 3);
6464

6565
// unnamed bitfield not included.
66-
static_assert(nonstatic_data_members_of(^^BitField).size() == 4);
66+
static_assert(nonstatic_data_members_of(^^BitField, {}).size() == 4);
6767
static_assert(size_of(^^BitField) == 4);
6868

6969
alignas(64) int i1;
@@ -116,4 +116,22 @@ static_assert(bit_size_of(dms2) == 0);
116116
static_assert(bit_size_of(dms3) == 3);
117117
static_assert(bit_size_of(dms4) == sizeof(int) * 8);
118118

119+
// ============
120+
// base_offsets
121+
// ============
122+
123+
namespace base_offsets {
124+
struct A { char a; };
125+
struct B { bool b; };
126+
struct C : A, B {};
127+
128+
static_assert(offset_of(bases_of(^^C, {})[0]) == std::meta::member_offset{0, 0});
129+
static_assert(offset_of(bases_of(^^C, {})[1]) == std::meta::member_offset{1, 0});
130+
131+
struct V { };
132+
struct D : V { virtual void fn() = 0; };
133+
static_assert(offset_of(bases_of(^^D, {})[0]) == std::meta::member_offset{0, 0});
134+
135+
} // namespace base_offsets
136+
119137
int main() { }

0 commit comments

Comments
 (0)