Skip to content

Commit e16474b

Browse files
committed
Revert "Revert "[clang] Add experimental option to omit the RTTI component from the vtable when -fno-rtti is used""
This attempts to reland 6385c1d but with a fix for the test failure.
1 parent 87e11ec commit e16474b

File tree

11 files changed

+155
-2
lines changed

11 files changed

+155
-2
lines changed

clang/include/clang/Basic/DiagnosticDriverKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,9 @@ def err_cc1_round_trip_mismatch : Error<
674674
def err_cc1_unbounded_vscale_min : Error<
675675
"minimum vscale must be an unsigned integer greater than 0">;
676676

677+
def err_drv_using_omit_rtti_component_without_no_rtti : Error<
678+
"-fexperimental-omit-vtable-rtti call only be used with -fno-rtti">;
679+
677680
def err_drv_ssp_missing_offset_argument : Error<
678681
"'%0' is used without '-mstack-protector-guard-offset', and there is no default">;
679682

clang/include/clang/Basic/LangOptions.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,9 @@ LANGOPT(SpeculativeLoadHardening, 1, 0, "Speculative load hardening enabled")
450450
LANGOPT(RelativeCXXABIVTables, 1, 0,
451451
"Use an ABI-incompatible v-table layout that uses relative references")
452452

453+
LANGOPT(OmitVTableRTTI, 1, 0,
454+
"Use an ABI-incompatible v-table layout that omits the RTTI component")
455+
453456
LANGOPT(VScaleMin, 32, 0, "Minimum vscale value")
454457
LANGOPT(VScaleMax, 32, 0, "Maximum vscale value")
455458

clang/include/clang/Driver/Options.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2671,6 +2671,12 @@ def fno_experimental_relative_cxx_abi_vtables :
26712671
Group<f_clang_Group>, Visibility<[ClangOption, CC1Option]>,
26722672
HelpText<"Do not use the experimental C++ class ABI for classes with virtual tables">;
26732673

2674+
defm experimental_omit_vtable_rtti : BoolFOption<"experimental-omit-vtable-rtti",
2675+
LangOpts<"OmitVTableRTTI">, DefaultFalse,
2676+
PosFlag<SetTrue, [], [CC1Option], "Omit">,
2677+
NegFlag<SetFalse, [], [CC1Option], "Do not omit">,
2678+
BothFlags<[], [CC1Option], " the RTTI component from virtual tables">>;
2679+
26742680
def fcxx_abi_EQ : Joined<["-"], "fc++-abi=">,
26752681
Group<f_clang_Group>, Visibility<[ClangOption, CC1Option]>,
26762682
HelpText<"C++ ABI to use. This will override the target C++ ABI.">;

clang/lib/AST/VTableBuilder.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -665,7 +665,11 @@ CharUnits VCallAndVBaseOffsetBuilder::getCurrentOffsetOffset() const {
665665
// vtable address point. (We subtract 3 to account for the information just
666666
// above the address point, the RTTI info, the offset to top, and the
667667
// vcall offset itself).
668-
int64_t OffsetIndex = -(int64_t)(3 + Components.size());
668+
size_t NumComponentsAboveAddrPoint = 3;
669+
if (Context.getLangOpts().OmitVTableRTTI)
670+
NumComponentsAboveAddrPoint--;
671+
int64_t OffsetIndex =
672+
-(int64_t)(NumComponentsAboveAddrPoint + Components.size());
669673

670674
// Under the relative ABI, the offset widths are 32-bit ints instead of
671675
// pointer widths.
@@ -1669,7 +1673,8 @@ void ItaniumVTableBuilder::LayoutPrimaryAndSecondaryVTables(
16691673
Components.push_back(VTableComponent::MakeOffsetToTop(OffsetToTop));
16701674

16711675
// Next, add the RTTI.
1672-
Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass));
1676+
if (!Context.getLangOpts().OmitVTableRTTI)
1677+
Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass));
16731678

16741679
uint64_t AddressPoint = Components.size();
16751680

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5526,6 +5526,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
55265526
Args.AddLastArg(CmdArgs, options::OPT_fexperimental_relative_cxx_abi_vtables,
55275527
options::OPT_fno_experimental_relative_cxx_abi_vtables);
55285528

5529+
Args.AddLastArg(CmdArgs, options::OPT_fexperimental_omit_vtable_rtti,
5530+
options::OPT_fno_experimental_omit_vtable_rtti);
5531+
55295532
// Handle segmented stacks.
55305533
Args.addOptInFlag(CmdArgs, options::OPT_fsplit_stack,
55315534
options::OPT_fno_split_stack);
@@ -6007,6 +6010,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
60076010
Args.AddLastArg(CmdArgs, options::OPT_fexperimental_relative_cxx_abi_vtables,
60086011
options::OPT_fno_experimental_relative_cxx_abi_vtables);
60096012

6013+
Args.AddLastArg(CmdArgs, options::OPT_fexperimental_omit_vtable_rtti,
6014+
options::OPT_fno_experimental_omit_vtable_rtti);
6015+
60106016
if (Arg *A = Args.getLastArg(options::OPT_ffuchsia_api_level_EQ))
60116017
A->render(Args, CmdArgs);
60126018

clang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4109,6 +4109,14 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
41094109
options::OPT_fno_experimental_relative_cxx_abi_vtables,
41104110
TargetCXXABI::usesRelativeVTables(T));
41114111

4112+
// RTTI is on by default.
4113+
bool HasRTTI = Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti, true);
4114+
Opts.OmitVTableRTTI =
4115+
Args.hasFlag(options::OPT_fexperimental_omit_vtable_rtti,
4116+
options::OPT_fno_experimental_omit_vtable_rtti, false);
4117+
if (Opts.OmitVTableRTTI && HasRTTI)
4118+
Diags.Report(diag::err_drv_using_omit_rtti_component_without_no_rtti);
4119+
41124120
for (const auto &A : Args.getAllArgValues(OPT_fmacro_prefix_map_EQ)) {
41134121
auto Split = StringRef(A).split('=');
41144122
Opts.MacroPrefixMap.insert(
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/// Check that -fexperimental-omit-vtable-rtti omits the RTTI component from
2+
/// the vtable.
3+
4+
// RUN: %clang_cc1 %s -triple=aarch64-unknown-linux-gnu -fno-rtti -fexperimental-omit-vtable-rtti -S -o - -emit-llvm | FileCheck -check-prefixes=POINTER,RTTI %s
5+
// RUN: %clang_cc1 %s -triple=aarch64-unknown-linux-gnu -fexperimental-relative-c++-abi-vtables -fno-rtti -fexperimental-omit-vtable-rtti -S -o - -emit-llvm | FileCheck -check-prefixes=RELATIVE,RTTI %s
6+
7+
/// Normally, the vtable would contain at least three components:
8+
/// - An offset to top
9+
/// - A pointer to the RTTI struct
10+
/// - A virtual function
11+
///
12+
/// Now vtables should have just two components.
13+
// POINTER: @_ZTV1A = unnamed_addr constant { [2 x ptr] } { [2 x ptr] [ptr null, ptr @_ZN1A3fooEv] }, align 8
14+
// RELATIVE: @_ZTV1A.local = private unnamed_addr constant { [2 x i32] } { [2 x i32] [i32 0, i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @_ZN1A3fooEv to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [2 x i32] }, ptr @_ZTV1A.local, i32 0, i32 0, i32 1) to i64)) to i32)] }, align 4
15+
// RELATIVE: @_ZTV1A = unnamed_addr alias { [2 x i32] }, ptr @_ZTV1A.local
16+
17+
/// None of these supplementary symbols should be emitted with -fno-rtti, but
18+
/// as a sanity check lets make sure they're not emitted also.
19+
// RTTI-NOT: @_ZTVN10__cxxabiv117__class_type_infoE
20+
// RTTI-NOT: @_ZTS1A
21+
// RTTI-NOT: @_ZTI1A
22+
23+
class A {
24+
public:
25+
virtual void foo();
26+
};
27+
28+
void A::foo() {}
29+
30+
void A_foo(A *a) {
31+
a->foo();
32+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/// Check that the offset to top calculation is adjusted to account for the
2+
/// omitted RTTI entry.
3+
4+
// RUN: %clang_cc1 %s -triple=aarch64-unknown-linux-gnu -fexperimental-omit-vtable-rtti -fno-rtti -S -o - -emit-llvm | FileCheck -check-prefixes=POINTER %s
5+
// RUN: %clang_cc1 %s -triple=aarch64-unknown-linux-gnu -fexperimental-relative-c++-abi-vtables -fexperimental-omit-vtable-rtti -fno-rtti -S -o - -emit-llvm | FileCheck -check-prefixes=RELATIVE %s
6+
7+
/// Some important things to check:
8+
/// - The n16 here represents the virtual thunk size. Normally this would be 24
9+
/// to represent 3 components (offset to top, RTTI component, vcall offset),
10+
/// but since one 8-byte component is removed, this is now 16.
11+
// POINTER-LABEL: @_ZTv0_n16_N7Derived1fEi(
12+
// POINTER-NEXT: entry:
13+
// POINTER: [[vtable:%.+]] = load ptr, ptr %this1, align 8
14+
15+
/// Same here - When getting the vbase offset, we subtract 2 pointer sizes
16+
/// instead of 3.
17+
// POINTER-NEXT: [[vbase_offset_ptr:%.+]] = getelementptr inbounds i8, ptr [[vtable]], i64 -16
18+
// POINTER-NEXT: [[vbase_offset:%.+]] = load i64, ptr [[vbase_offset_ptr]], align 8
19+
// POINTER-NEXT: [[adj_this:%.+]] = getelementptr inbounds i8, ptr %this1, i64 [[vbase_offset]]
20+
// POINTER: [[call:%.+]] = tail call noundef i32 @_ZN7Derived1fEi(ptr noundef{{[^,]*}} [[adj_this]], i32 noundef {{.*}})
21+
// POINTER: ret i32 [[call]]
22+
23+
/// For relative vtables, it's almost the same except the offset sizes are
24+
/// halved.
25+
// RELATIVE-LABEL: @_ZTv0_n8_N7Derived1fEi(
26+
// RELATIVE-NEXT: entry:
27+
// RELATIVE: [[vtable:%.+]] = load ptr, ptr %this1, align 8
28+
// RELATIVE-NEXT: [[vbase_offset_ptr:%.+]] = getelementptr inbounds i8, ptr [[vtable]], i64 -8
29+
// RELATIVE-NEXT: [[vbase_offset:%.+]] = load i32, ptr [[vbase_offset_ptr]], align 4
30+
// RELATIVE-NEXT: [[adj_this:%.+]] = getelementptr inbounds i8, ptr %this1, i32 [[vbase_offset]]
31+
// RELATIVE: [[call:%.+]] = tail call noundef i32 @_ZN7Derived1fEi(ptr noundef{{[^,]*}} [[adj_this]], i32 noundef {{.*}})
32+
// RELATIVE: ret i32 [[call]]
33+
34+
class Base {
35+
public:
36+
virtual int f(int x);
37+
38+
private:
39+
long x;
40+
};
41+
42+
class Derived : public virtual Base {
43+
public:
44+
virtual int f(int x);
45+
46+
private:
47+
long y;
48+
};
49+
50+
int Base::f(int x) { return x + 1; }
51+
int Derived::f(int x) { return x + 2; }
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/// Ensure -fdump-vtable-layout omits the rtti component when passed -fexperimental-omit-vtable-rtti.
2+
3+
// RUN: %clang_cc1 %s -triple=aarch64-unknown-linux-gnu -fno-rtti -fexperimental-omit-vtable-rtti -emit-llvm-only -fdump-vtable-layouts | FileCheck %s
4+
5+
// CHECK: Vtable for 'A' (2 entries).
6+
// CHECK-NEXT: 0 | offset_to_top (0)
7+
// CHECK-NEXT: -- (A, 0) vtable address --
8+
// CHECK-NEXT: 1 | void A::foo()
9+
10+
class A {
11+
public:
12+
virtual void foo();
13+
};
14+
15+
void A::foo() {}
16+
17+
void A_foo(A *a) {
18+
a->foo();
19+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// RUN: %clangxx --target=aarch64-unknown-linux -fno-rtti -Xclang -fexperimental-omit-vtable-rtti -c %s -### 2>&1 | FileCheck %s --check-prefix=OMIT
2+
// RUN: %clangxx --target=aarch64-unknown-linux -fno-rtti -Xclang -fno-experimental-omit-vtable-rtti -c %s -### 2>&1 | FileCheck %s --check-prefix=NO-OMIT
3+
4+
// OMIT: "-fexperimental-omit-vtable-rtti"
5+
// NO-OMIT-NOT: "-fexperimental-omit-vtable-rtti"
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/// Ensure that -fexperimental-omit-vtable-rtti is only allowed if rtti is
2+
/// disabled.
3+
4+
// UNSUPPORTED: system-windows
5+
6+
// RUN: not %clang -c -Xclang -fexperimental-omit-vtable-rtti %s 2>&1 | FileCheck -check-prefix=ERROR %s
7+
// RUN: not %clang -c -Xclang -fexperimental-omit-vtable-rtti -frtti %s 2>&1 | FileCheck -check-prefix=ERROR %s
8+
// RUN: not %clang -c -Xclang -fexperimental-omit-vtable-rtti -fno-rtti -frtti %s 2>&1 | FileCheck -check-prefix=ERROR %s
9+
10+
// RUN: %clang -c -Xclang -fexperimental-omit-vtable-rtti -fno-rtti %s 2>&1 | FileCheck -check-prefix=NO-ERROR %s --allow-empty
11+
// RUN: %clang -c -Xclang -fno-experimental-omit-vtable-rtti -frtti %s 2>&1 | FileCheck -check-prefix=NO-ERROR %s --allow-empty
12+
// RUN: %clang -c -Xclang -fexperimental-omit-vtable-rtti -Xclang -fno-experimental-omit-vtable-rtti -frtti %s 2>&1 | FileCheck -check-prefix=NO-ERROR %s --allow-empty
13+
14+
// ERROR: -fexperimental-omit-vtable-rtti call only be used with -fno-rtti
15+
// NO-ERROR-NOT: -fexperimental-omit-vtable-rtti call only be used with -fno-rtti

0 commit comments

Comments
 (0)