aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/CodeGen/CGClass.cpp13
-rw-r--r--test/CodeGenCXX/derived-to-virtual-base-class-calls-final.cpp16
2 files changed, 27 insertions, 2 deletions
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index 2a92258b84..a7b8f65978 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -180,8 +180,17 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
llvm::Value *VirtualOffset = 0;
- if (VBase)
- VirtualOffset = GetVirtualBaseClassOffset(Value, Derived, VBase);
+ if (VBase) {
+ if (Derived->hasAttr<FinalAttr>()) {
+ VirtualOffset = 0;
+
+ const ASTRecordLayout &Layout = getContext().getASTRecordLayout(Derived);
+
+ uint64_t VBaseOffset = Layout.getVBaseClassOffsetInBits(VBase);
+ NonVirtualOffset += VBaseOffset / 8;
+ } else
+ VirtualOffset = GetVirtualBaseClassOffset(Value, Derived, VBase);
+ }
// Apply the offsets.
Value = ApplyNonVirtualAndVirtualOffset(*this, Value, NonVirtualOffset,
diff --git a/test/CodeGenCXX/derived-to-virtual-base-class-calls-final.cpp b/test/CodeGenCXX/derived-to-virtual-base-class-calls-final.cpp
new file mode 100644
index 0000000000..e332f40200
--- /dev/null
+++ b/test/CodeGenCXX/derived-to-virtual-base-class-calls-final.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+
+struct A { int i; };
+struct B { int j; };
+struct C : A, B { int k; };
+
+struct D final : virtual C {
+ D();
+ virtual void f();
+};
+
+// CHECK: define %struct.B* @_Z1fR1D
+B &f(D &d) {
+ // CHECK-NOT: load i8**
+ return d;
+}