|
| 1 | +// RUN: split-file %s %t |
| 2 | + |
| 3 | + |
| 4 | +//--- incomplete_struct |
| 5 | + |
| 6 | +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %t/incomplete_struct -o %t/incomplete_struct.cir |
| 7 | +// RUN: FileCheck %s --input-file=%t/incomplete_struct.cir --check-prefix=CHECK1 |
| 8 | + |
| 9 | +// Forward declaration of the record is never defined, so it is created as |
| 10 | +// an incomplete struct in CIR and will remain as such. |
| 11 | + |
| 12 | +// CHECK1: ![[INC_STRUCT:.+]] = !cir.record<struct "IncompleteStruct" incomplete> |
| 13 | +struct IncompleteStruct; |
| 14 | +// CHECK1: testIncompleteStruct(%arg0: !cir.ptr<![[INC_STRUCT]]> |
| 15 | +void testIncompleteStruct(struct IncompleteStruct *s) {}; |
| 16 | + |
| 17 | + |
| 18 | + |
| 19 | +//--- mutated_struct |
| 20 | + |
| 21 | +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %t/mutated_struct -o %t/mutated_struct.cir |
| 22 | +// RUN: FileCheck %s --input-file=%t/mutated_struct.cir --check-prefix=CHECK2 |
| 23 | + |
| 24 | +// Foward declaration of the struct is followed by usage, then definition. |
| 25 | +// This means it will initially be created as incomplete, then completed. |
| 26 | + |
| 27 | +// CHECK2: ![[COMPLETE:.+]] = !cir.record<struct "ForwardDeclaredStruct" {!s32i}> |
| 28 | +// CHECK2: testForwardDeclaredStruct(%arg0: !cir.ptr<![[COMPLETE]]> |
| 29 | +struct ForwardDeclaredStruct; |
| 30 | +void testForwardDeclaredStruct(struct ForwardDeclaredStruct *fds) {}; |
| 31 | +struct ForwardDeclaredStruct { |
| 32 | + int testVal; |
| 33 | +}; |
| 34 | + |
| 35 | + |
| 36 | + |
| 37 | +//--- recursive_struct |
| 38 | + |
| 39 | +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %t/recursive_struct -o %t/recursive_struct.cir |
| 40 | +// RUN: FileCheck --check-prefix=CHECK3 --input-file=%t/recursive_struct.cir %s |
| 41 | + |
| 42 | +// Struct is initially forward declared since the self-reference is generated |
| 43 | +// first. Then, once the type is fully generated, it is completed. |
| 44 | + |
| 45 | +// CHECK3: ![[STRUCT:.+]] = !cir.record<struct "RecursiveStruct" {!s32i, !cir.ptr<!cir.record<struct "RecursiveStruct">>}> |
| 46 | +struct RecursiveStruct { |
| 47 | + int value; |
| 48 | + struct RecursiveStruct *next; |
| 49 | +}; |
| 50 | +// CHECK3: testRecursiveStruct(%arg0: !cir.ptr<![[STRUCT]]> |
| 51 | +void testRecursiveStruct(struct RecursiveStruct *arg) { |
| 52 | + // CHECK3: %[[#NEXT:]] = cir.get_member %{{.+}}[1] {name = "next"} : !cir.ptr<![[STRUCT]]> -> !cir.ptr<!cir.ptr<![[STRUCT]]>> |
| 53 | + // CHECK3: %[[#DEREF:]] = cir.load{{.*}} %[[#NEXT]] : !cir.ptr<!cir.ptr<![[STRUCT]]>>, !cir.ptr<![[STRUCT]]> |
| 54 | + // CHECK3: cir.get_member %[[#DEREF]][0] {name = "value"} : !cir.ptr<![[STRUCT]]> -> !cir.ptr<!s32i> |
| 55 | + arg->next->value; |
| 56 | +} |
| 57 | + |
| 58 | + |
| 59 | + |
| 60 | +//--- indirect_recursive_struct |
| 61 | + |
| 62 | +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %t/indirect_recursive_struct -o %t/indirect_recursive_struct.cir |
| 63 | +// RUN: FileCheck --check-prefix=CHECK4 --input-file=%t/indirect_recursive_struct.cir %s |
| 64 | + |
| 65 | +// Node B refers to A, and vice-versa, so a forward declaration is used to |
| 66 | +// ensure the classes can be defined. Since types alias are not yet supported |
| 67 | +// in recursive type, each struct is expanded until there are no more recursive |
| 68 | +// types, or all the recursive types are self references. |
| 69 | + |
| 70 | +// CHECK4: ![[B:.+]] = !cir.record<struct "StructNodeB" {!s32i, !cir.ptr<!cir.record<struct "StructNodeA" {!s32i, !cir.ptr<!cir.record<struct "StructNodeB">>} |
| 71 | +// CHECK4: ![[A:.+]] = !cir.record<struct "StructNodeA" {!s32i, !cir.ptr<![[B]]>}> |
| 72 | +struct StructNodeB; |
| 73 | +struct StructNodeA { |
| 74 | + int value; |
| 75 | + struct StructNodeB *next; |
| 76 | +}; |
| 77 | +struct StructNodeB { |
| 78 | + int value; |
| 79 | + struct StructNodeA *next; |
| 80 | +}; |
| 81 | + |
| 82 | +void testIndirectSelfReference(struct StructNodeA arg) { |
| 83 | + // CHECK4: %[[#V1:]] = cir.get_member %{{.+}}[1] {name = "next"} : !cir.ptr<![[A]]> -> !cir.ptr<!cir.ptr<![[B]]>> |
| 84 | + // CHECK4: %[[#V2:]] = cir.load{{.*}} %[[#V1]] : !cir.ptr<!cir.ptr<![[B]]>>, !cir.ptr<![[B]]> |
| 85 | + // CHECK4: %[[#V3:]] = cir.get_member %[[#V2]][1] {name = "next"} : !cir.ptr<![[B]]> -> !cir.ptr<!cir.ptr<![[A]]>> |
| 86 | + // CHECK4: %[[#V4:]] = cir.load{{.*}} %[[#V3]] : !cir.ptr<!cir.ptr<![[A]]>>, !cir.ptr<![[A]]> |
| 87 | + // CHECK4: cir.get_member %[[#V4]][0] {name = "value"} : !cir.ptr<![[A]]> -> !cir.ptr<!s32i> |
| 88 | + arg.next->next->value; |
| 89 | +} |
| 90 | + |
| 91 | + |
| 92 | + |
| 93 | +//--- complex_struct |
| 94 | + |
| 95 | +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %t/complex_struct -o %t/complex_struct.cir |
| 96 | +// RUN: FileCheck --check-prefix=CHECK5 --input-file=%t/complex_struct.cir %s |
| 97 | + |
| 98 | +// A sizeable complex struct just to double check that stuff is working. |
| 99 | +// CHECK5: !cir.record<struct "anon.0" {!cir.ptr<!cir.record<struct "A" {!cir.record<struct "anon.0">, !cir.record<struct "B" {!cir.ptr<!cir.record<struct "B">>, !cir.record<struct "C" {!cir.ptr<!cir.record<struct "A">>, !cir.ptr<!cir.record<struct "B">>, !cir.ptr<!cir.record<struct "C">>}>, !cir.record<union "anon.1" {!cir.ptr<!cir.record<struct "A">>, !cir.record<struct "anon.2" {!cir.ptr<!cir.record<struct "B">>}>}>}>}>>}> |
| 100 | +// CHECK5: !cir.record<struct "C" {!cir.ptr<!cir.record<struct "A" {!rec_anon2E0, !cir.record<struct "B" {!cir.ptr<!cir.record<struct "B">>, !cir.record<struct "C">, !cir.record<union "anon.1" {!cir.ptr<!cir.record<struct "A">>, !cir.record<struct "anon.2" {!cir.ptr<!cir.record<struct "B">>}>}>}>}>>, !cir.ptr<!cir.record<struct "B" {!cir.ptr<!cir.record<struct "B">>, !cir.record<struct "C">, !cir.record<union "anon.1" {!cir.ptr<!cir.record<struct "A" {!rec_anon2E0, !cir.record<struct "B">}>>, !cir.record<struct "anon.2" {!cir.ptr<!cir.record<struct "B">>}>}>}>>, !cir.ptr<!cir.record<struct "C">>}> |
| 101 | +// CHECK5: !cir.record<struct "anon.2" {!cir.ptr<!cir.record<struct "B" {!cir.ptr<!cir.record<struct "B">>, !rec_C, !cir.record<union "anon.1" {!cir.ptr<!cir.record<struct "A" {!rec_anon2E0, !cir.record<struct "B">}>>, !cir.record<struct "anon.2">}>}>>}> |
| 102 | +// CHECK5: !cir.record<union "anon.1" {!cir.ptr<!cir.record<struct "A" {!rec_anon2E0, !cir.record<struct "B" {!cir.ptr<!cir.record<struct "B">>, !rec_C, !cir.record<union "anon.1">}>}>>, !rec_anon2E2}> |
| 103 | +// CHECK5: !cir.record<struct "B" {!cir.ptr<!cir.record<struct "B">>, !rec_C, !rec_anon2E1}> |
| 104 | +// CHECK5: !cir.record<struct "A" {!rec_anon2E0, !rec_B}> |
| 105 | +struct A { |
| 106 | + struct { |
| 107 | + struct A *a1; |
| 108 | + }; |
| 109 | + struct B { |
| 110 | + struct B *b1; |
| 111 | + struct C { |
| 112 | + struct A *a2; |
| 113 | + struct B *b2; |
| 114 | + struct C *c1; |
| 115 | + } c; |
| 116 | + union { |
| 117 | + struct A *a2; |
| 118 | + struct { |
| 119 | + struct B *b3; |
| 120 | + }; |
| 121 | + } u; |
| 122 | + } b; |
| 123 | +}; |
| 124 | +void test(struct A *a){}; |
0 commit comments