diff options
Diffstat (limited to 'test/Sema')
-rw-r--r-- | test/Sema/128bitint.c | 19 | ||||
-rw-r--r-- | test/Sema/arm-asm.c | 7 | ||||
-rw-r--r-- | test/Sema/builtins-decl.c | 5 | ||||
-rw-r--r-- | test/Sema/callingconv.c | 8 | ||||
-rw-r--r-- | test/Sema/static-array.c | 46 | ||||
-rw-r--r-- | test/Sema/tentative-decls.c | 5 | ||||
-rw-r--r-- | test/Sema/warn-documentation.cpp | 60 | ||||
-rw-r--r-- | test/Sema/warn-type-safety-mpi-hdf5.c | 307 | ||||
-rw-r--r-- | test/Sema/warn-type-safety.c | 152 | ||||
-rw-r--r-- | test/Sema/warn-type-safety.cpp | 71 |
10 files changed, 661 insertions, 19 deletions
diff --git a/test/Sema/128bitint.c b/test/Sema/128bitint.c index ddad835..600c25a 100644 --- a/test/Sema/128bitint.c +++ b/test/Sema/128bitint.c @@ -18,3 +18,22 @@ long long Signed64 = 123456789012345678901234567890i128; // expected-warning {{i unsigned long long UnsignedTooBig = 123456789012345678901234567890; // expected-warning {{integer constant is too large for its type}} __uint128_t Unsigned128 = 123456789012345678901234567890Ui128; unsigned long long Unsigned64 = 123456789012345678901234567890Ui128; // expected-warning {{implicit conversion from 'unsigned __int128' to 'unsigned long long' changes value from 123456789012345678901234567890 to 14083847773837265618}} + +// Ensure we don't crash when user passes 128-bit values to type safety +// attributes. +void pointer_with_type_tag_arg_num_1(void *buf, int datatype) + __attribute__(( pointer_with_type_tag(mpi,0x10000000000000001i128,1) )); // expected-error {{attribute parameter 2 is out of bounds}} + +void pointer_with_type_tag_arg_num_2(void *buf, int datatype) + __attribute__(( pointer_with_type_tag(mpi,1,0x10000000000000001i128) )); // expected-error {{attribute parameter 3 is out of bounds}} + +void MPI_Send(void *buf, int datatype) __attribute__(( pointer_with_type_tag(mpi,1,2) )); + +static const __uint128_t mpi_int_wrong __attribute__(( type_tag_for_datatype(mpi,int) )) = 0x10000000000000001i128; // expected-error {{'type_tag_for_datatype' attribute requires the initializer to be an integer constant expression that can be represented by a 64 bit integer}} +static const int mpi_int __attribute__(( type_tag_for_datatype(mpi,int) )) = 10; + +void test(int *buf) +{ + MPI_Send(buf, 0x10000000000000001i128); // expected-warning {{implicit conversion from '__int128' to 'int' changes value}} +} + diff --git a/test/Sema/arm-asm.c b/test/Sema/arm-asm.c new file mode 100644 index 0000000..3fc0eeb --- /dev/null +++ b/test/Sema/arm-asm.c @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 %s -triple armv7-apple-darwin -verify -fsyntax-only + +void f (void) { + int Val; + asm volatile ("lw (r1), %0[val]": "=&b"(Val)); // expected-error {{invalid output constraint '=&b' in asm}} + return; +} diff --git a/test/Sema/builtins-decl.c b/test/Sema/builtins-decl.c index 19bdb84..d6b004a 100644 --- a/test/Sema/builtins-decl.c +++ b/test/Sema/builtins-decl.c @@ -6,3 +6,8 @@ extern unsigned int __builtin_ia32_crc32qi (unsigned int, unsigned char); extern unsigned int __builtin_ia32_crc32hi (unsigned int, unsigned short); extern unsigned int __builtin_ia32_crc32si (unsigned int, unsigned int); + +// GCC documents these as unsigned, but they are defined with a signed argument. +extern int __builtin_ffs(int); +extern int __builtin_ffsl(long); +extern int __builtin_ffsll(long long); diff --git a/test/Sema/callingconv.c b/test/Sema/callingconv.c index 25669f0..6c844a3 100644 --- a/test/Sema/callingconv.c +++ b/test/Sema/callingconv.c @@ -36,6 +36,14 @@ void (__attribute__((cdecl)) *pctest2)() = ctest2; typedef void (__attribute__((fastcall)) *Handler) (float *); Handler H = foo; +int __attribute__((pcs("aapcs", "aapcs"))) pcs1(void); // expected-error {{attribute takes one argument}} +int __attribute__((pcs())) pcs2(void); // expected-error {{attribute takes one argument}} +int __attribute__((pcs(pcs1))) pcs3(void); // expected-error {{attribute takes one argument}} +int __attribute__((pcs(0))) pcs4(void); // expected-error {{'pcs' attribute requires parameter 1 to be a string}} +int __attribute__((pcs("aapcs"))) pcs5(void); // no-error +int __attribute__((pcs("aapcs-vfp"))) pcs6(void); // no-error +int __attribute__((pcs("foo"))) pcs7(void); // expected-error {{Invalid PCS type}} + // PR6361 void ctest3(); void __attribute__((cdecl)) ctest3() {} diff --git a/test/Sema/static-array.c b/test/Sema/static-array.c index 2d4b968..5ca693b 100644 --- a/test/Sema/static-array.c +++ b/test/Sema/static-array.c @@ -1,12 +1,9 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -fblocks -verify %s void cat0(int a[static 0]) {} // expected-warning {{'static' has no effect on zero-length arrays}} void cat(int a[static 3]) {} // expected-note 2 {{callee declares array parameter as static here}} -typedef int i3[static 3]; -void tcat(i3 a) {} - void vat(int i, int a[static i]) {} // expected-note {{callee declares array parameter as static here}} void f(int *p) { @@ -20,12 +17,41 @@ void f(int *p) { cat(c); cat(p); - tcat(0); // expected-warning {{null passed to a callee which requires a non-null argument}} - tcat(a); // expected-warning {{array argument is too small; contains 2 elements, callee requires at least 3}} - tcat(b); - tcat(c); - tcat(p); - vat(1, 0); // expected-warning {{null passed to a callee which requires a non-null argument}} vat(3, b); } + + +typedef int td[static 3]; // expected-error {{'static' used in array declarator outside of function prototype}} +typedef void(*fp)(int[static 42]); // no-warning + +void g(void) { + int a[static 42]; // expected-error {{'static' used in array declarator outside of function prototype}} + + int b[const 10]; // expected-error {{type qualifier used in array declarator outside of function prototype}} + int c[volatile 10]; // expected-error {{type qualifier used in array declarator outside of function prototype}} + int d[restrict 10]; // expected-error {{type qualifier used in array declarator outside of function prototype}} + + int e[static restrict 1]; // expected-error {{'static' used in array declarator outside of function prototype}} +} + +void h(int [static const 10][42]); // no-warning + +void i(int [10] + [static 42]); // expected-error {{'static' used in non-outermost array type derivation}} + +void j(int [10] + [const 42]); // expected-error {{type qualifier used in non-outermost array type derivation}} + +void k(int (*x)[static 10]); // expected-error {{'static' used in non-outermost array type derivation}} +void l(int (x)[static 10]); // no-warning +void m(int *x[static 10]); // no-warning +void n(int *(x)[static 10]); // no-warning + +void o(int (x[static 10])(void)); // expected-error{{'x' declared as array of functions of type 'int (void)'}} +void p(int (^x)[static 10]); // expected-error{{block pointer to non-function type is invalid}} +void q(int (^x[static 10])()); // no-warning + +void r(x) + int x[restrict]; // no-warning +{} diff --git a/test/Sema/tentative-decls.c b/test/Sema/tentative-decls.c index b15537b..e14540b 100644 --- a/test/Sema/tentative-decls.c +++ b/test/Sema/tentative-decls.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -fsyntax-only -verify +// RUN: %clang_cc1 %s -fsyntax-only -Wprivate-extern -verify // PR3310 struct a x1; // expected-note 2{{forward declaration of 'struct a'}} @@ -32,7 +32,8 @@ int i2 = 3; // expected-error{{non-static declaration of 'i2' follows static dec static int i3 = 5; extern int i3; -__private_extern__ int pExtern; +// rdar://7703982 +__private_extern__ int pExtern; // expected-warning {{Use of __private_extern__ on tentative definition has unexpected behaviour}} int pExtern = 0; int i4; diff --git a/test/Sema/warn-documentation.cpp b/test/Sema/warn-documentation.cpp index 16ba429..d99520b 100644 --- a/test/Sema/warn-documentation.cpp +++ b/test/Sema/warn-documentation.cpp @@ -624,13 +624,9 @@ class test_attach37 { /// \brief\author Aaa /// \tparam T Aaa void test_attach38(int aaa, int bbb); -}; -// expected-warning@+1 {{empty paragraph passed to '\brief' command}} -/// \brief\author Aaa -/// \tparam T Aaa -template<typename T> -void test_attach37<T>::test_attach38(int aaa, int bbb) {} + void test_attach39(int aaa, int bbb); +}; // expected-warning@+2 {{empty paragraph passed to '\brief' command}} // expected-warning@+2 {{template parameter 'T' not found in the template declaration}} @@ -639,6 +635,29 @@ void test_attach37<T>::test_attach38(int aaa, int bbb) {} template<> void test_attach37<int>::test_attach38(int aaa, int bbb) {} +// expected-warning@+1 {{empty paragraph passed to '\brief' command}} +/// \brief\author Aaa +/// \tparam T Aaa +template<typename T> +void test_attach37<T>::test_attach39(int aaa, int bbb) {} + +// We used to emit warning that parameter 'a' is not found because we parsed +// the comment in context of the redeclaration which does not have parameter +// names. +template <typename T> +struct test_attach38 { + /*! + \param a First param + \param b Second param + */ + template <typename B> + void test_attach39(T a, B b); +}; + +template <> +template <typename B> +void test_attach38<int>::test_attach39(int, B); + // PR13411, reduced. We used to crash on this. /** @@ -652,7 +671,7 @@ void test_nocrash1(int); /// \param\brief void test_nocrash2(int); -// PR13593 +// PR13593, example 1 and 2 /** * Bla. @@ -668,3 +687,30 @@ template <typename> void test_nocrash3() { } + +// PR13593, example 3 + +/** + * aaa + */ +template <typename T> +inline T test_nocrash5(T a1) +{ + return a1; +} + +/// +//, + +inline void test_nocrash6() +{ + test_nocrash5(1); +} + +// We used to crash on this. + +/*! + Blah. +*/ +typedef const struct test_nocrash7 * test_nocrash8; + diff --git a/test/Sema/warn-type-safety-mpi-hdf5.c b/test/Sema/warn-type-safety-mpi-hdf5.c new file mode 100644 index 0000000..9c2ee96 --- /dev/null +++ b/test/Sema/warn-type-safety-mpi-hdf5.c @@ -0,0 +1,307 @@ +// RUN: %clang_cc1 -std=c99 -DOPEN_MPI -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c99 -DMPICH -fsyntax-only -verify %s +// RUN: %clang_cc1 -x c++ -std=c++98 -DOPEN_MPI -fsyntax-only -verify %s +// RUN: %clang_cc1 -x c++ -std=c++98 -DMPICH -fsyntax-only -verify %s +// +// RUN: %clang_cc1 -std=c99 -DOPEN_MPI -fno-signed-char -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c99 -DMPICH -fno-signed-char -fsyntax-only -verify %s + +//===--- limits.h mock ----------------------------------------------------===// + +#ifdef __CHAR_UNSIGNED__ +#define CHAR_MIN 0 +#define CHAR_MAX (__SCHAR_MAX__*2 +1) +#else +#define CHAR_MIN (-__SCHAR_MAX__-1) +#define CHAR_MAX __SCHAR_MAX__ +#endif + +//===--- mpi.h mock -------------------------------------------------------===// + +#define NULL ((void *)0) + +#ifdef OPEN_MPI +typedef struct ompi_datatype_t *MPI_Datatype; +#endif + +#ifdef MPICH +typedef int MPI_Datatype; +#endif + +int MPI_Send(void *buf, int count, MPI_Datatype datatype) + __attribute__(( pointer_with_type_tag(mpi,1,3) )); + +int MPI_Gather(void *sendbuf, int sendcount, MPI_Datatype sendtype, + void *recvbuf, int recvcount, MPI_Datatype recvtype) + __attribute__(( pointer_with_type_tag(mpi,1,3), pointer_with_type_tag(mpi,4,6) )); + +#ifdef OPEN_MPI +// OpenMPI and LAM/MPI-style datatype definitions + +#define OMPI_PREDEFINED_GLOBAL(type, global) ((type) &(global)) + +#define MPI_DATATYPE_NULL OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_datatype_null) +#define MPI_FLOAT OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_float) +#define MPI_INT OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_int) +#define MPI_LONG OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_long) +#define MPI_LONG_LONG_INT OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_long_long_int) +#define MPI_CHAR OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_char) + +#define MPI_FLOAT_INT OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_float_int) +#define MPI_2INT OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_2int) + +#define MPI_IN_PLACE ((void *) 1) + +extern struct ompi_predefined_datatype_t ompi_mpi_datatype_null __attribute__(( type_tag_for_datatype(mpi,void,must_be_null) )); +extern struct ompi_predefined_datatype_t ompi_mpi_float __attribute__(( type_tag_for_datatype(mpi,float) )); +extern struct ompi_predefined_datatype_t ompi_mpi_int __attribute__(( type_tag_for_datatype(mpi,int) )); +extern struct ompi_predefined_datatype_t ompi_mpi_long __attribute__(( type_tag_for_datatype(mpi,long) )); +extern struct ompi_predefined_datatype_t ompi_mpi_long_long_int __attribute__(( type_tag_for_datatype(mpi,long long int) )); +extern struct ompi_predefined_datatype_t ompi_mpi_char __attribute__(( type_tag_for_datatype(mpi,char) )); + +struct ompi_struct_mpi_float_int {float f; int i;}; +extern struct ompi_predefined_datatype_t ompi_mpi_float_int __attribute__(( type_tag_for_datatype(mpi, struct ompi_struct_mpi_float_int, layout_compatible) )); + +struct ompi_struct_mpi_2int {int i1; int i2;}; +extern struct ompi_predefined_datatype_t ompi_mpi_2int __attribute__(( type_tag_for_datatype(mpi, struct ompi_struct_mpi_2int, layout_compatible) )); +#endif + +#ifdef MPICH +// MPICH2 and MVAPICH2-style datatype definitions + +#define MPI_COMM_WORLD ((MPI_Comm) 0x44000000) + +#define MPI_DATATYPE_NULL ((MPI_Datatype) 0xa0000000) +#define MPI_FLOAT ((MPI_Datatype) 0xa0000001) +#define MPI_INT ((MPI_Datatype) 0xa0000002) +#define MPI_LONG ((MPI_Datatype) 0xa0000003) +#define MPI_LONG_LONG_INT ((MPI_Datatype) 0xa0000004) +#define MPI_CHAR ((MPI_Datatype) 0xa0000005) + +#define MPI_FLOAT_INT ((MPI_Datatype) 0xa0000006) +#define MPI_2INT ((MPI_Datatype) 0xa0000007) + +#define MPI_IN_PLACE (void *) -1 + +static const MPI_Datatype mpich_mpi_datatype_null __attribute__(( type_tag_for_datatype(mpi,void,must_be_null) )) = 0xa0000000; +static const MPI_Datatype mpich_mpi_float __attribute__(( type_tag_for_datatype(mpi,float) )) = 0xa0000001; +static const MPI_Datatype mpich_mpi_int __attribute__(( type_tag_for_datatype(mpi,int) )) = 0xa0000002; +static const MPI_Datatype mpich_mpi_long __attribute__(( type_tag_for_datatype(mpi,long) )) = 0xa0000003; +static const MPI_Datatype mpich_mpi_long_long_int __attribute__(( type_tag_for_datatype(mpi,long long int) )) = 0xa0000004; +static const MPI_Datatype mpich_mpi_char __attribute__(( type_tag_for_datatype(mpi,char) )) = 0xa0000005; + +struct mpich_struct_mpi_float_int { float f; int i; }; +struct mpich_struct_mpi_2int { int i1; int i2; }; +static const MPI_Datatype mpich_mpi_float_int __attribute__(( type_tag_for_datatype(mpi, struct mpich_struct_mpi_float_int, layout_compatible) )) = 0xa0000006; +static const MPI_Datatype mpich_mpi_2int __attribute__(( type_tag_for_datatype(mpi, struct mpich_struct_mpi_2int, layout_compatible) )) = 0xa0000007; +#endif + +//===--- HDF5 headers mock ------------------------------------------------===// + +typedef int hid_t; +void H5open(void); + +#ifndef HDF_PRIVATE +#define H5OPEN H5open(), +#else +#define H5OPEN +#endif + +#define H5T_NATIVE_CHAR (CHAR_MIN?H5T_NATIVE_SCHAR:H5T_NATIVE_UCHAR) +#define H5T_NATIVE_SCHAR (H5OPEN H5T_NATIVE_SCHAR_g) +#define H5T_NATIVE_UCHAR (H5OPEN H5T_NATIVE_UCHAR_g) +#define H5T_NATIVE_INT (H5OPEN H5T_NATIVE_INT_g) +#define H5T_NATIVE_LONG (H5OPEN H5T_NATIVE_LONG_g) + +hid_t H5T_NATIVE_SCHAR_g __attribute__(( type_tag_for_datatype(hdf5,signed char) )); +hid_t H5T_NATIVE_UCHAR_g __attribute__(( type_tag_for_datatype(hdf5,unsigned char) )); +hid_t H5T_NATIVE_INT_g __attribute__(( type_tag_for_datatype(hdf5,int) )); +hid_t H5T_NATIVE_LONG_g __attribute__(( type_tag_for_datatype(hdf5,long) )); + +void H5Dwrite(hid_t mem_type_id, const void *buf) __attribute__(( pointer_with_type_tag(hdf5,2,1) )); + +//===--- Tests ------------------------------------------------------------===// + +//===--- MPI + +struct pair_float_int +{ + float f; int i; +}; + +struct pair_int_int +{ + int i1; int i2; +}; + +void test_mpi_predefined_types( + int *int_buf, + long *long_buf1, + long *long_buf2, + void *void_buf, + struct pair_float_int *pfi, + struct pair_int_int *pii) +{ + char char_buf[255]; + + // Layout-compatible scalar types. + MPI_Send(int_buf, 1, MPI_INT); // no-warning + + // Layout-compatible class types. + MPI_Send(pfi, 1, MPI_FLOAT_INT); // no-warning + MPI_Send(pii, 1, MPI_2INT); // no-warning + + // Layout-incompatible scalar types. + MPI_Send(long_buf1, 1, MPI_INT); // expected-warning {{argument type 'long *' doesn't match specified 'mpi' type tag that requires 'int *'}} + + // Layout-incompatible class types. + MPI_Send(pii, 1, MPI_FLOAT_INT); // expected-warning {{argument type 'struct pair_int_int *' doesn't match specified 'mpi' type tag}} + MPI_Send(pfi, 1, MPI_2INT); // expected-warning {{argument type 'struct pair_float_int *' doesn't match specified 'mpi' type tag}} + + // Layout-incompatible class-scalar types. + MPI_Send(long_buf1, 1, MPI_2INT); // expected-warning {{argument type 'long *' doesn't match specified 'mpi' type tag}} + + // Function with two buffers. + MPI_Gather(long_buf1, 1, MPI_INT, // expected-warning {{argument type 'long *' doesn't match specified 'mpi' type tag that requires 'int *'}} + long_buf2, 1, MPI_INT); // expected-warning {{argument type 'long *' doesn't match specified 'mpi' type tag that requires 'int *'}} + + // Array buffers should work like pointer buffers. + MPI_Send(char_buf, 255, MPI_CHAR); // no-warning + + // Explicit casts should not be dropped. + MPI_Send((int *) char_buf, 255, MPI_INT); // no-warning + MPI_Send((int *) char_buf, 255, MPI_CHAR); // expected-warning {{argument type 'int *' doesn't match specified 'mpi' type tag that requires 'char *'}} + + // `void*' buffer should never warn. + MPI_Send(void_buf, 255, MPI_CHAR); // no-warning + + // We expect that MPI_IN_PLACE is `void*', shouldn't warn. + MPI_Gather(MPI_IN_PLACE, 0, MPI_INT, + int_buf, 1, MPI_INT); + + // Special handling for MPI_DATATYPE_NULL: buffer pointer should be either + // a `void*' pointer or a null pointer constant. + MPI_Gather(NULL, 0, MPI_DATATYPE_NULL, // no-warning + int_buf, 1, MPI_INT); + + MPI_Gather(int_buf, 0, MPI_DATATYPE_NULL, // expected-warning {{specified mpi type tag requires a null pointer}} + int_buf, 1, MPI_INT); +} + +MPI_Datatype my_int_datatype __attribute__(( type_tag_for_datatype(mpi,int) )); + +struct S1 { int a; int b; }; +MPI_Datatype my_s1_datatype __attribute__(( type_tag_for_datatype(mpi,struct S1) )); + +// Layout-compatible to S1, but should be treated as a different type. +struct S2 { int a; int b; }; +MPI_Datatype my_s2_datatype __attribute__(( type_tag_for_datatype(mpi,struct S2) )); + +void test_user_types(int *int_buf, + long *long_buf, + struct S1 *s1_buf, + struct S2 *s2_buf) +{ + MPI_Send(int_buf, 1, my_int_datatype); // no-warning + MPI_Send(long_buf, 1, my_int_datatype); // expected-warning {{argument type 'long *' doesn't match specified 'mpi' type tag that requires 'int *'}} + + MPI_Send(s1_buf, 1, my_s1_datatype); // no-warning + MPI_Send(s1_buf, 1, my_s2_datatype); // expected-warning {{argument type 'struct S1 *' doesn't match specified 'mpi' type tag that requires 'struct S2 *'}} + + MPI_Send(long_buf, 1, my_s1_datatype); // expected-warning {{argument type 'long *' doesn't match specified 'mpi' type tag that requires 'struct S1 *'}} + MPI_Send(s1_buf, 1, MPI_INT); // expected-warning {{argument type 'struct S1 *' doesn't match specified 'mpi' type tag that requires 'int *'}} +} + +MPI_Datatype my_unknown_datatype; + +void test_not_annotated(int *int_buf, + long *long_buf, + MPI_Datatype type) +{ + // Using 'MPI_Datatype's without attributes should not produce warnings. + MPI_Send(long_buf, 1, my_unknown_datatype); // no-warning + MPI_Send(int_buf, 1, type); // no-warning +} + +struct S1_compat { int a; int b; }; +MPI_Datatype my_s1_compat_datatype + __attribute__(( type_tag_for_datatype(mpi, struct S1_compat, layout_compatible) )); + +struct S3 { int a; long b; double c; double d; struct S1 s1; }; +struct S3_compat { int a; long b; double c; double d; struct S2 s2; }; +MPI_Datatype my_s3_compat_datatype + __attribute__(( type_tag_for_datatype(mpi, struct S3_compat, layout_compatible) )); + +struct S4 { char c; }; +struct S4_compat { signed char c; }; +MPI_Datatype my_s4_compat_datatype + __attribute__(( type_tag_for_datatype(mpi, struct S4_compat, layout_compatible) )); + +union U1 { int a; long b; double c; double d; struct S1 s1; }; +union U1_compat { long b; double c; struct S2 s; int a; double d; }; +MPI_Datatype my_u1_compat_datatype + __attribute__(( type_tag_for_datatype(mpi, union U1_compat, layout_compatible) )); + +union U2 { int a; long b; double c; struct S1 s1; }; +MPI_Datatype my_u2_datatype + __attribute__(( type_tag_for_datatype(mpi, union U2, layout_compatible) )); + +void test_layout_compatibility(struct S1 *s1_buf, struct S3 *s3_buf, + struct S4 *s4_buf, + union U1 *u1_buf, union U2 *u2_buf) +{ + MPI_Send(s1_buf, 1, my_s1_compat_datatype); // no-warning + MPI_Send(s3_buf, 1, my_s3_compat_datatype); // no-warning + MPI_Send(s1_buf, 1, my_s3_compat_datatype); // expected-warning {{argument type 'struct S1 *' doesn't match specified 'mpi' type tag}} + MPI_Send(s4_buf, 1, my_s4_compat_datatype); // expected-warning {{argument type 'struct S4 *' doesn't match specified 'mpi' type tag}} + MPI_Send(u1_buf, 1, my_u1_compat_datatype); // no-warning + MPI_Send(u1_buf, 1, my_u2_datatype); // expected-warning {{argument type 'union U1 *' doesn't match specified 'mpi' type tag}} + MPI_Send(u2_buf, 1, my_u1_compat_datatype); // expected-warning {{argument type 'union U2 *' doesn't match specified 'mpi' type tag}} +} + +// There is an MPI_REAL predefined in MPI, but some existing MPI programs do +// this. +typedef float real; +#define MPI_REAL MPI_FLOAT + +void test_mpi_real_user_type(real *real_buf, float *float_buf) +{ + MPI_Send(real_buf, 1, MPI_REAL); // no-warning + MPI_Send(real_buf, 1, MPI_FLOAT); // no-warning + MPI_Send(float_buf, 1, MPI_REAL); // no-warning + MPI_Send(float_buf, 1, MPI_FLOAT); // no-warning +} + +//===--- HDF5 + +void test_hdf5(char *char_buf, + signed char *schar_buf, + unsigned char *uchar_buf, + int *int_buf, + long *long_buf) +{ + H5Dwrite(H5T_NATIVE_CHAR, char_buf); // no-warning +#ifdef __CHAR_UNSIGNED__ + H5Dwrite(H5T_NATIVE_CHAR, schar_buf); // expected-warning {{argument type 'signed char *' doesn't match specified 'hdf5' type tag that requires 'unsigned char *'}} + H5Dwrite(H5T_NATIVE_CHAR, uchar_buf); // no-warning +#else + H5Dwrite(H5T_NATIVE_CHAR, schar_buf); // no-warning + H5Dwrite(H5T_NATIVE_CHAR, uchar_buf); // expected-warning {{argument type 'unsigned char *' doesn't match specified 'hdf5' type tag that requires 'signed char *'}} +#endif + H5Dwrite(H5T_NATIVE_SCHAR, schar_buf); // no-warning + H5Dwrite(H5T_NATIVE_UCHAR, uchar_buf); // no-warning + H5Dwrite(H5T_NATIVE_INT, int_buf); // no-warning + H5Dwrite(H5T_NATIVE_LONG, long_buf); // no-warning + +#ifdef __CHAR_UNSIGNED__ + H5Dwrite(H5T_NATIVE_CHAR, int_buf); // expected-warning {{argument type 'int *' doesn't match specified 'hdf5' type tag that requires 'unsigned char *'}} +#else + H5Dwrite(H5T_NATIVE_CHAR, int_buf); // expected-warning {{argument type 'int *' doesn't match specified 'hdf5' type tag that requires 'signed char *'}} +#endif + H5Dwrite(H5T_NATIVE_INT, long_buf); // expected-warning {{argument type 'long *' doesn't match specified 'hdf5' type tag that requires 'int *'}} + + // FIXME: we should warn here, but it will cause false positives because + // different kinds may use same magic values. + //H5Dwrite(MPI_INT, int_buf); +} + diff --git a/test/Sema/warn-type-safety.c b/test/Sema/warn-type-safety.c new file mode 100644 index 0000000..6f548aa --- /dev/null +++ b/test/Sema/warn-type-safety.c @@ -0,0 +1,152 @@ +// RUN: %clang_cc1 -std=c99 -fsyntax-only -verify %s +// RUN: %clang_cc1 -x c++ -std=c++98 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c99 -fno-signed-char -fsyntax-only -verify %s + +struct A {}; + +typedef struct A *MPI_Datatype; + +int wrong1(void *buf, MPI_Datatype datatype) + __attribute__(( pointer_with_type_tag )); // expected-error {{attribute requires parameter 1 to be an identifier}} + +int wrong2(void *buf, MPI_Datatype datatype) + __attribute__(( pointer_with_type_tag(mpi,0,7) )); // expected-error {{attribute parameter 2 is out of bounds}} + +int wrong3(void *buf, MPI_Datatype datatype) + __attribute__(( pointer_with_type_tag(mpi,3,7) )); // expected-error {{attribute parameter 2 is out of bounds}} + +int wrong4(void *buf, MPI_Datatype datatype) + __attribute__(( pointer_with_type_tag(mpi,1,0) )); // expected-error {{attribute parameter 3 is out of bounds}} + +int wrong5(void *buf, MPI_Datatype datatype) + __attribute__(( pointer_with_type_tag(mpi,1,3) )); // expected-error {{attribute parameter 3 is out of bounds}} + +int wrong6(void *buf, MPI_Datatype datatype) + __attribute__(( pointer_with_type_tag(mpi,0x8000000000000001ULL,1) )); // expected-error {{attribute parameter 2 is out of bounds}} + +extern int x; + +int wrong7(void *buf, MPI_Datatype datatype) + __attribute__(( pointer_with_type_tag(mpi,x,2) )); // expected-error {{attribute requires parameter 2 to be an integer constant}} + +int wrong8(void *buf, MPI_Datatype datatype) + __attribute__(( pointer_with_type_tag(mpi,1,x) )); // expected-error {{attribute requires parameter 3 to be an integer constant}} + +int wrong9 __attribute__(( pointer_with_type_tag(mpi,1,2) )); // expected-error {{attribute only applies to functions and methods}} + +int wrong10(double buf, MPI_Datatype type) + __attribute__(( pointer_with_type_tag(mpi,1,2) )); // expected-error {{'pointer_with_type_tag' attribute only applies to pointer arguments}} + + +extern struct A datatype_wrong1 + __attribute__(( type_tag_for_datatype )); // expected-error {{attribute requires parameter 1 to be an identifier}} + +extern struct A datatype_wrong2 + __attribute__(( type_tag_for_datatype(mpi,1,2) )); // expected-error {{expected a type}} + +extern struct A datatype_wrong3 + __attribute__(( type_tag_for_datatype(mpi,not_a_type) )); // expected-error {{unknown type name 'not_a_type'}} + +extern struct A datatype_wrong4 + __attribute__(( type_tag_for_datatype(mpi,int,int) )); // expected-error {{expected identifier}} + +extern struct A datatype_wrong5 + __attribute__(( type_tag_for_datatype(mpi,int,not_a_flag) )); // expected-error {{invalid comparison flag 'not_a_flag'}} + +extern struct A datatype_wrong6 + __attribute__(( type_tag_for_datatype(mpi,int,layout_compatible,not_a_flag) )); // expected-error {{invalid comparison flag 'not_a_flag'}} + + +// Using a tag with kind A in a place where the function requires kind B should +// warn. + +void A_func(void *ptr, void *tag) __attribute__(( pointer_with_type_tag(a,1,2) )); + +extern struct A A_tag __attribute__(( type_tag_for_datatype(a,int) )); +extern struct A B_tag __attribute__(( type_tag_for_datatype(b,int) )); + +void C_func(void *ptr, int tag) __attribute__(( pointer_with_type_tag(c,1,2) )); + +static const int C_tag __attribute__(( type_tag_for_datatype(c,int) )) = 10; +static const int D_tag __attribute__(( type_tag_for_datatype(d,int) )) = 20; + +void test_tag_mismatch(int *ptr) +{ + A_func(ptr, &A_tag); // no-warning + A_func(ptr, &B_tag); // expected-warning {{this type tag was not designed to be used with this function}} + C_func(ptr, C_tag); // no-warning + C_func(ptr, D_tag); // expected-warning {{this type tag was not designed to be used with this function}} + C_func(ptr, 10); // no-warning + C_func(ptr, 20); // should warn, but may cause false positives +} + +// Check that we look through typedefs in the special case of allowing 'char' +// to be matched with 'signed char' or 'unsigned char'. +void E_func(void *ptr, int tag) __attribute__(( pointer_with_type_tag(e,1,2) )); + +typedef char E_char; +typedef char E_char_2; +typedef signed char E_char_signed; +typedef unsigned char E_char_unsigned; + +static const int E_tag __attribute__(( type_tag_for_datatype(e,E_char) )) = 10; + +void test_char_typedef(char *char_buf, + E_char_2 *e_char_buf, + E_char_signed *e_char_signed_buf, + E_char_unsigned *e_char_unsigned_buf) +{ + E_func(char_buf, E_tag); + E_func(e_char_buf, E_tag); +#ifdef __CHAR_UNSIGNED__ + E_func(e_char_signed_buf, E_tag); // expected-warning {{argument type 'E_char_signed *' (aka 'signed char *') doesn't match specified 'e' type tag that requires 'E_char *' (aka 'char *')}} + E_func(e_char_unsigned_buf, E_tag); +#else + E_func(e_char_signed_buf, E_tag); + E_func(e_char_unsigned_buf, E_tag); // expected-warning {{argument type 'E_char_unsigned *' (aka 'unsigned char *') doesn't match specified 'e' type tag that requires 'E_char *' (aka 'char *')}} +#endif +} + +// Tests for argument_with_type_tag. + +#define F_DUPFD 10 +#define F_SETLK 20 + +struct flock { }; + +static const int F_DUPFD_tag __attribute__(( type_tag_for_datatype(fcntl,int) )) = F_DUPFD; +static const int F_SETLK_tag __attribute__(( type_tag_for_datatype(fcntl,struct flock *) )) = F_SETLK; + +int fcntl(int fd, int cmd, ...) __attribute__(( argument_with_type_tag(fcntl,3,2) )); + +void test_argument_with_type_tag(struct flock *f) +{ + fcntl(0, F_DUPFD, 10); // no-warning + fcntl(0, F_SETLK, f); // no-warning + + fcntl(0, F_SETLK, 10); // expected-warning {{argument type 'int' doesn't match specified 'fcntl' type tag that requires 'struct flock *'}} + fcntl(0, F_DUPFD, f); // expected-warning {{argument type 'struct flock *' doesn't match specified 'fcntl' type tag that requires 'int'}} +} + +void test_tag_expresssion(int b) { + fcntl(0, b ? F_DUPFD : F_SETLK, 10); // no-warning + fcntl(0, b + F_DUPFD, 10); // no-warning + fcntl(0, (b, F_DUPFD), 10); // expected-warning {{expression result unused}} +} + +// Check that using 64-bit magic values as tags works and tag values do not +// overflow internally. +void F_func(void *ptr, unsigned long long tag) __attribute__((pointer_with_type_tag(f,1,2) )); + +static const unsigned long long F_tag1 __attribute__(( type_tag_for_datatype(f,int) )) = 0xFFFFFFFFFFFFFFFFULL; +static const unsigned long long F_tag2 __attribute__(( type_tag_for_datatype(f,float) )) = 0xFFFFFFFFULL; + +void test_64bit_magic(int *int_ptr, float *float_ptr) +{ + F_func(int_ptr, 0xFFFFFFFFFFFFFFFFULL); + F_func(int_ptr, 0xFFFFFFFFULL); // expected-warning {{argument type 'int *' doesn't match specified 'f' type tag that requires 'float *'}} + F_func(float_ptr, 0xFFFFFFFFFFFFFFFFULL); // expected-warning {{argument type 'float *' doesn't match specified 'f' type tag that requires 'int *'}} + F_func(float_ptr, 0xFFFFFFFFULL); +} + + diff --git a/test/Sema/warn-type-safety.cpp b/test/Sema/warn-type-safety.cpp new file mode 100644 index 0000000..d053fba --- /dev/null +++ b/test/Sema/warn-type-safety.cpp @@ -0,0 +1,71 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +typedef struct ompi_datatype_t *MPI_Datatype; + +#define OMPI_PREDEFINED_GLOBAL(type, global) ((type) &(global)) + +#define MPI_FLOAT OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_float) +#define MPI_INT OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_int) +#define MPI_NULL OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_null) + +extern struct ompi_predefined_datatype_t ompi_mpi_float __attribute__(( type_tag_for_datatype(mpi,float) )); +extern struct ompi_predefined_datatype_t ompi_mpi_int __attribute__(( type_tag_for_datatype(mpi,int) )); +extern struct ompi_predefined_datatype_t ompi_mpi_null __attribute__(( type_tag_for_datatype(mpi,void,must_be_null) )); + +int f(int x) { return x; } +static const int wrong_init __attribute__(( type_tag_for_datatype(zzz,int) )) = f(100); // expected-error {{'type_tag_for_datatype' attribute requires the initializer to be an integral constant expression}} + +//===--- Tests ------------------------------------------------------------===// +// Check that hidden 'this' is handled correctly. + +class C +{ +public: + void f1(void *buf, int count, MPI_Datatype datatype) + __attribute__(( pointer_with_type_tag(mpi,5,6) )); // expected-error {{attribute parameter 2 is out of bounds}} + + void f2(void *buf, int count, MPI_Datatype datatype) + __attribute__(( pointer_with_type_tag(mpi,2,5) )); // expected-error {{attribute parameter 3 is out of bounds}} + + void f3(void *buf, int count, MPI_Datatype datatype) + __attribute__(( pointer_with_type_tag(mpi,1,5) )); // expected-error {{attribute is invalid for the implicit this argument}} + + void f4(void *buf, int count, MPI_Datatype datatype) + __attribute__(( pointer_with_type_tag(mpi,2,1) )); // expected-error {{attribute is invalid for the implicit this argument}} + + void MPI_Send(void *buf, int count, MPI_Datatype datatype) + __attribute__(( pointer_with_type_tag(mpi,2,4) )); // no-error +}; + +// Check that we don't crash on type and value dependent expressions. +template<int a> +void value_dep(void *buf, int count, MPI_Datatype datatype) + __attribute__(( pointer_with_type_tag(mpi,a,5) )); // expected-error {{attribute requires parameter 2 to be an integer constant}} + +class OperatorIntStar +{ +public: + operator int*(); +}; + +void test1(C *c, int *int_buf) +{ + c->MPI_Send(int_buf, 1, MPI_INT); // no-warning + c->MPI_Send(int_buf, 1, MPI_FLOAT); // expected-warning {{argument type 'int *' doesn't match specified 'mpi' type tag that requires 'float *'}} + + OperatorIntStar i; + c->MPI_Send(i, 1, MPI_INT); // no-warning + c->MPI_Send(i, 1, MPI_FLOAT); // expected-warning {{argument type 'int *' doesn't match specified 'mpi' type tag that requires 'float *'}} +} + +template<typename T> +void test2(C *c, int *int_buf, T tag) +{ + c->MPI_Send(int_buf, 1, tag); // no-warning +} + +void test3(C *c, int *int_buf) { + test2(c, int_buf, MPI_INT); + test2(c, int_buf, MPI_NULL); +} + |