
This enables us to compile C++ code with nested structures. The necessary support for this was already in place, but we were hitting an NYI error in a place where the implementation only needed to check for base classes. Base classes really aren't implemented yet, so the error is left in place but it is now behind a check for a non-zero number of bases so that the simple case is unblocked.
96 lines
3.3 KiB
C++
96 lines
3.3 KiB
C++
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
|
|
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
|
|
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
|
|
// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
|
|
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
|
|
// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
|
|
|
|
struct IncompleteS;
|
|
IncompleteS *p;
|
|
|
|
// CIR: cir.global external @p = #cir.ptr<null> : !cir.ptr<!rec_IncompleteS>
|
|
// LLVM: @p = global ptr null
|
|
// OGCG: @p = global ptr null, align 8
|
|
|
|
struct CompleteS {
|
|
int a;
|
|
char b;
|
|
};
|
|
|
|
CompleteS cs;
|
|
|
|
// CIR: cir.global external @cs = #cir.zero : !rec_CompleteS
|
|
// LLVM-DAG: @cs = global %struct.CompleteS zeroinitializer
|
|
// OGCG-DAG: @cs = global %struct.CompleteS zeroinitializer, align 4
|
|
|
|
void f(void) {
|
|
IncompleteS *p;
|
|
}
|
|
|
|
// CIR: cir.func @_Z1fv()
|
|
// CIR-NEXT: cir.alloca !cir.ptr<!rec_IncompleteS>, !cir.ptr<!cir.ptr<!rec_IncompleteS>>, ["p"]
|
|
// CIR-NEXT: cir.return
|
|
|
|
// LLVM: define void @_Z1fv()
|
|
// LLVM-NEXT: %[[P:.*]] = alloca ptr, i64 1, align 8
|
|
// LLVM-NEXT: ret void
|
|
|
|
// OGCG: define{{.*}} void @_Z1fv()
|
|
// OGCG-NEXT: entry:
|
|
// OGCG-NEXT: %[[P:.*]] = alloca ptr, align 8
|
|
// OGCG-NEXT: ret void
|
|
|
|
char f2(CompleteS &s) {
|
|
return s.b;
|
|
}
|
|
|
|
// CIR: cir.func @_Z2f2R9CompleteS(%[[ARG_S:.*]]: !cir.ptr<!rec_CompleteS>{{.*}})
|
|
// CIR: %[[S_ADDR:.*]] = cir.alloca !cir.ptr<!rec_CompleteS>, !cir.ptr<!cir.ptr<!rec_CompleteS>>, ["s", init, const]
|
|
// CIR: cir.store %[[ARG_S]], %[[S_ADDR]]
|
|
// CIR: %[[S_REF:.*]] = cir.load{{.*}} %[[S_ADDR]]
|
|
// CIR: %[[S_ADDR2:.*]] = cir.get_member %[[S_REF]][1] {name = "b"}
|
|
// CIR: %[[S_B:.*]] = cir.load{{.*}} %[[S_ADDR2]]
|
|
|
|
// LLVM: define i8 @_Z2f2R9CompleteS(ptr %[[ARG_S:.*]])
|
|
// LLVM: %[[S_ADDR:.*]] = alloca ptr
|
|
// LLVM: store ptr %[[ARG_S]], ptr %[[S_ADDR]]
|
|
// LLVM: %[[S_REF:.*]] = load ptr, ptr %[[S_ADDR]], align 8
|
|
// LLVM: %[[S_ADDR2:.*]] = getelementptr %struct.CompleteS, ptr %[[S_REF]], i32 0, i32 1
|
|
// LLVM: %[[S_B:.*]] = load i8, ptr %[[S_ADDR2]]
|
|
|
|
// OGCG: define{{.*}} i8 @_Z2f2R9CompleteS(ptr{{.*}} %[[ARG_S:.*]])
|
|
// OGCG: entry:
|
|
// OGCG: %[[S_ADDR:.*]] = alloca ptr
|
|
// OGCG: store ptr %[[ARG_S]], ptr %[[S_ADDR]]
|
|
// OGCG: %[[S_REF:.*]] = load ptr, ptr %[[S_ADDR]]
|
|
// OGCG: %[[S_ADDR2:.*]] = getelementptr inbounds nuw %struct.CompleteS, ptr %[[S_REF]], i32 0, i32 1
|
|
// OGCG: %[[S_B:.*]] = load i8, ptr %[[S_ADDR2]]
|
|
|
|
struct Inner {
|
|
int n;
|
|
};
|
|
|
|
struct Outer {
|
|
Inner i;
|
|
};
|
|
|
|
void f3() {
|
|
Outer o;
|
|
o.i.n;
|
|
}
|
|
|
|
// CIR: cir.func @_Z2f3v()
|
|
// CIR: %[[O:.*]] = cir.alloca !rec_Outer, !cir.ptr<!rec_Outer>, ["o"]
|
|
// CIR: %[[O_I:.*]] = cir.get_member %[[O]][0] {name = "i"}
|
|
// CIR: %[[O_I_N:.*]] = cir.get_member %[[O_I]][0] {name = "n"}
|
|
|
|
// LLVM: define{{.*}} void @_Z2f3v()
|
|
// LLVM: %[[O:.*]] = alloca %struct.Outer, i64 1, align 4
|
|
// LLVM: %[[O_I:.*]] = getelementptr %struct.Outer, ptr %[[O]], i32 0, i32 0
|
|
// LLVM: %[[O_I_N:.*]] = getelementptr %struct.Inner, ptr %[[O_I]], i32 0, i32 0
|
|
|
|
// OGCG: define{{.*}} void @_Z2f3v()
|
|
// OGCG: %[[O:.*]] = alloca %struct.Outer, align 4
|
|
// OGCG: %[[O_I:.*]] = getelementptr inbounds nuw %struct.Outer, ptr %[[O]], i32 0, i32 0
|
|
// OGCG: %[[O_I_N:.*]] = getelementptr inbounds nuw %struct.Inner, ptr %[[O_I]], i32 0, i32 0
|