|
| 1 | +// A few tests of multi-decls with complex types, with and without |
| 2 | +// -itypes-for-extern. These tests cannot be included in multivardecls.c because |
| 3 | +// compiling that entire file with -itypes-for-extern -addcr would produce an |
| 4 | +// unrelated error in the typedef multi-decl test: see the first example in |
| 5 | +// https://github.com/correctcomputation/checkedc-clang/issues/740. |
| 6 | + |
| 7 | +// RUN: rm -rf %t* |
| 8 | + |
| 9 | +// RUN: 3c -base-dir=%S -addcr -alltypes %s -- | FileCheck -match-full-lines -check-prefixes="CHECK_ALL","CHECK" %s |
| 10 | +// RUN: 3c -base-dir=%S -addcr %s -- | FileCheck -match-full-lines -check-prefixes="CHECK_NOALL","CHECK" %s |
| 11 | +// RUN: 3c -base-dir=%S -addcr %s -- | %clang -c -fcheckedc-extension -x c -o /dev/null - |
| 12 | +// RUN: 3c -base-dir=%S -alltypes -output-dir=%t.checked %s -- |
| 13 | +// RUN: 3c -base-dir=%t.checked -alltypes %t.checked/multivardecls_complex_types.c -- | diff %t.checked/multivardecls_complex_types.c - |
| 14 | + |
| 15 | +// RUN: 3c -base-dir=%S -itypes-for-extern -alltypes -addcr %s -- | FileCheck -match-full-lines -check-prefixes="CHECK_ITE_ALL","CHECK_ITE" %s |
| 16 | +// RUN: 3c -base-dir=%S -itypes-for-extern -addcr %s -- | FileCheck -match-full-lines -check-prefixes="CHECK_ITE_NOALL","CHECK_ITE" %s |
| 17 | +// RUN: 3c -base-dir=%S -itypes-for-extern -alltypes -addcr %s -- | %clang -c -fcheckedc-extension -x c -o /dev/null - |
| 18 | +// RUN: 3c -base-dir=%S -itypes-for-extern -alltypes -output-dir=%t.checked_ITE %s -- |
| 19 | +// RUN: 3c -base-dir=%t.checked_ITE -itypes-for-extern -alltypes %t.checked_ITE/multivardecls_complex_types.c -- | diff %t.checked_ITE/multivardecls_complex_types.c - |
| 20 | + |
| 21 | +// A multi-decl with a mix of pointers and arrays, including an "unchecked |
| 22 | +// pointer to constant size array" member that would trigger a known bug in |
| 23 | +// mkString (item 5 of |
| 24 | +// https://github.com/correctcomputation/checkedc-clang/issues/703), |
| 25 | +// demonstrating that unchanged multi-decl members whose base type wasn't |
| 26 | +// renamed use Decl::print (which doesn't have this bug). |
| 27 | +// |
| 28 | +// `m_force_rewrite` gets converted and forces the |
| 29 | +// multi-decl to be broken up even though nothing else changes when -alltypes is |
| 30 | +// off. |
| 31 | +// |
| 32 | +// `m_implicit_itype` and `m_change_with_bounds` together test that 3C includes |
| 33 | +// Checked C annotations in the range to be replaced (for both changed and |
| 34 | +// unchanged multi-decl members) rather than leaving them to duplicate the |
| 35 | +// annotations in the newly inserted declaration. |
| 36 | +int m_const_arr0[10], *m_const_arr1[10], (*m_p_const_arr_wild)[10] = 1, |
| 37 | + (*m_p_const_arr_chk)[10], *m_implicit_itype : count(2), |
| 38 | + **m_change_with_bounds : count(2); |
| 39 | +//CHECK_ALL: int m_const_arr0 _Checked[10]; |
| 40 | +//CHECK_NOALL: int m_const_arr0[10]; |
| 41 | +//CHECK_ALL: _Ptr<int> m_const_arr1 _Checked[10] = {((void *)0)}; |
| 42 | +//CHECK_NOALL: int *m_const_arr1[10]; |
| 43 | +//CHECK: int (*m_p_const_arr_wild)[10] = 1; |
| 44 | +//CHECK_ALL: _Ptr<int _Checked[10]> m_p_const_arr_chk = ((void *)0); |
| 45 | +//CHECK_NOALL: _Ptr<int[10]> m_p_const_arr_chk = ((void *)0); |
| 46 | +// 3C doesn't have proper support for itypes on variables: if a variable has an |
| 47 | +// existing itype, 3C uses the checked side as the variable's original type. So |
| 48 | +// 3C treats m_implicit_itype as having original type _Array_ptr<int>, but since |
| 49 | +// the solved type is the same, 3C uses Decl::print for the unchanged multi-decl |
| 50 | +// member and preserves the original declaration with the itype. When 3C gains |
| 51 | +// proper itype support for variables, it should generate an actual rewrite to |
| 52 | +// the fully checked type if nothing else in the program prevents it from doing |
| 53 | +// so. |
| 54 | +//CHECK: int *m_implicit_itype : count(2); |
| 55 | +// In this case, the solved type changes and shows up in the output. |
| 56 | +//CHECK: _Array_ptr<_Ptr<int>> m_change_with_bounds : count(2) = ((void *)0); |
| 57 | + |
| 58 | +// Test the same multi-decl with -itypes-for-extern. |
| 59 | +//CHECK_ITE_ALL: int m_const_arr0[10] : itype(int _Checked[10]); |
| 60 | +//CHECK_ITE_NOALL: int m_const_arr0[10]; |
| 61 | +//CHECK_ITE_ALL: int *m_const_arr1[10] : itype(_Ptr<int> _Checked[10]) = {((void *)0)}; |
| 62 | +//CHECK_ITE_NOALL: int *m_const_arr1[10]; |
| 63 | +//CHECK_ITE: int (*m_p_const_arr_wild)[10] = 1; |
| 64 | +//CHECK_ITE_ALL: int (*m_p_const_arr_chk)[10] : itype(_Ptr<int _Checked[10]>) = ((void *)0); |
| 65 | +//CHECK_ITE_NOALL: int (*m_p_const_arr_chk)[10] : itype(_Ptr<int[10]>) = ((void *)0); |
| 66 | +//CHECK_ITE: int *m_implicit_itype : count(2); |
| 67 | +//CHECK_ITE: int **m_change_with_bounds : itype(_Array_ptr<_Ptr<int>>) count(2) = ((void *)0); |
| 68 | + |
| 69 | +// A similar multi-decl with an unnamed inline struct, which forces the use of |
| 70 | +// mkString. We can't include (*s_p_const_arr_*)[10] because it would trigger |
| 71 | +// the previously mentioned mkString bug and produce output that doesn't |
| 72 | +// compile. `s` serves just to give the struct a shorter generated name. |
| 73 | +struct { int *x; } s, s_const_arr0[10], *s_const_arr1[10], |
| 74 | + // The only way a variable of unnamed struct type can have an itype is if it |
| 75 | + // comes implicitly from a bounds annotation, since we have no name to refer |
| 76 | + // to the struct in a written itype. |
| 77 | + *s_implicit_itype : count(2), **s_change_with_bounds : count(2); |
| 78 | +//CHECK: struct s_struct_1 { _Ptr<int> x; }; |
| 79 | +//CHECK: struct s_struct_1 s; |
| 80 | +//CHECK_ALL: struct s_struct_1 s_const_arr0 _Checked[10]; |
| 81 | +//CHECK_NOALL: struct s_struct_1 s_const_arr0[10]; |
| 82 | +//CHECK_ALL: _Ptr<struct s_struct_1> s_const_arr1 _Checked[10] = {((void *)0)}; |
| 83 | +// The reason this isn't `_Ptr<struct s_struct_1>` is probably the "outer wild |
| 84 | +// -> inner wild" constraint |
| 85 | +// (https://github.com/correctcomputation/checkedc-clang/issues/656). |
| 86 | +//CHECK_NOALL: struct s_struct_1 *s_const_arr1[10]; |
| 87 | +// Like with m_implicit_itype above, 3C treats s_implicit_itype as having type |
| 88 | +// _Array_ptr<struct s_struct_1>, but now 3C uses mkString and that type |
| 89 | +// actually shows up in the output: not a great result, but at least we test |
| 90 | +// that it isn't any worse and that the bounds annotation is preserved. Since |
| 91 | +// s_implicit_itype is now the only member of its "multi-decl", if the user |
| 92 | +// manually edits it back to an itype, there won't be another multi-decl breakup |
| 93 | +// to cause 3C to mess it up again. |
| 94 | +//CHECK: _Array_ptr<struct s_struct_1> s_implicit_itype : count(2); |
| 95 | +//CHECK: _Array_ptr<_Ptr<struct s_struct_1>> s_change_with_bounds : count(2) = ((void *)0); |
| 96 | + |
| 97 | +// Test the same multi-decl with -itypes-for-extern. |
| 98 | +//CHECK_ITE: struct s_struct_1 { int *x : itype(_Ptr<int>); }; |
| 99 | +//CHECK_ITE: struct s_struct_1 s; |
| 100 | +//CHECK_ITE_ALL: struct s_struct_1 s_const_arr0[10] : itype(struct s_struct_1 _Checked[10]); |
| 101 | +//CHECK_ITE_NOALL: struct s_struct_1 s_const_arr0[10]; |
| 102 | +//CHECK_ITE_ALL: struct s_struct_1 *s_const_arr1[10] : itype(_Ptr<struct s_struct_1> _Checked[10]) = {((void *)0)}; |
| 103 | +//CHECK_ITE_NOALL: struct s_struct_1 *s_const_arr1[10]; |
| 104 | +// The type of s_implicit_type is still loaded as _Array_ptr<struct s_struct_1>, |
| 105 | +// but it is downgraded back to an itype by -itypes-for-extern. As long as 3C |
| 106 | +// lacks real support for itypes on variables, this is probably the behavior we |
| 107 | +// want with -itypes-for-extern in this very unusual case. |
| 108 | +//CHECK_ITE: struct s_struct_1 *s_implicit_itype : itype(_Array_ptr<struct s_struct_1>) count(2); |
| 109 | +//CHECK_ITE: struct s_struct_1 **s_change_with_bounds : itype(_Array_ptr<_Ptr<struct s_struct_1>>) count(2) = ((void *)0); |
0 commit comments