| // RUN: %clang_cc1 -Wall -Wno-unused -Wno-uninitialized -verify %s |
| |
| #define CFI_UNCHECKED_CALLEE __attribute__((cfi_unchecked_callee)) |
| |
| void unchecked(void) CFI_UNCHECKED_CALLEE {} |
| void checked(void) {} |
| |
| void (*checked_ptr)(void) = unchecked; // expected-warning{{implicit conversion from 'void (void) __attribute__((cfi_unchecked_callee))' to 'void (*)(void)' discards 'cfi_unchecked_callee' attribute}} |
| void (CFI_UNCHECKED_CALLEE *unchecked_ptr)(void) = unchecked; |
| void (CFI_UNCHECKED_CALLEE *from_normal)(void) = checked; |
| void (CFI_UNCHECKED_CALLEE *c_no_function_decay)(void) = &unchecked; |
| |
| typedef void (CFI_UNCHECKED_CALLEE unchecked_func_t)(void); |
| typedef void (checked_func_t)(void); |
| typedef void (CFI_UNCHECKED_CALLEE *cfi_unchecked_func_ptr_t)(void); |
| typedef void (*checked_func_ptr_t)(void); |
| checked_func_t *cfi_func = unchecked; // expected-warning{{implicit conversion from 'void (void) __attribute__((cfi_unchecked_callee))' to 'void (*)(void)' discards 'cfi_unchecked_callee' attribute}} |
| unchecked_func_t *unchecked_func = unchecked; |
| |
| void CFI_UNCHECKED_CALLEE after_ret_type(void); |
| CFI_UNCHECKED_CALLEE void before_ret_type(void); |
| void (* CFI_UNCHECKED_CALLEE after_name)(void); |
| |
| void UsageOnImproperTypes() { |
| int CFI_UNCHECKED_CALLEE i; // expected-warning{{'cfi_unchecked_callee' only applies to function types; type here is 'int'}} |
| |
| /// The attribute must be used only on functions with prototypes. The omission of `void` means it is not prototyped. |
| void (CFI_UNCHECKED_CALLEE *noproto)(void); // expecteed-warning{{'cfi_unchecked_callee' attribute only applies to non-K&R-style functions}} |
| } |
| |
| /// Explicit casts suppress the warning. |
| void CheckCasts() { |
| void (*should_warn)(void) = unchecked; // expected-warning{{implicit conversion from 'void (void) __attribute__((cfi_unchecked_callee))' to 'void (*)(void)' discards 'cfi_unchecked_callee' attribute}} |
| |
| void (*no_warn_c_style_cast)(void) = (void (*)(void))unchecked; |
| |
| struct B {} CFI_UNCHECKED_CALLEE b; // expected-warning{{'cfi_unchecked_callee' attribute only applies to functions and methods}} |
| struct CFI_UNCHECKED_CALLEE C {} c; // expected-warning{{'cfi_unchecked_callee' attribute only applies to functions and methods}} |
| CFI_UNCHECKED_CALLEE struct D {} d; // expected-warning{{'cfi_unchecked_callee' only applies to function types; type here is 'struct D'}} |
| |
| void *ptr2 = (void *)unchecked; |
| } |
| |
| int checked_arg_func(checked_func_t *checked_func); |
| |
| void CheckDifferentConstructions() { |
| void (CFI_UNCHECKED_CALLEE *arr[10])(void); |
| void (*cfi_elem)(void) = arr[1]; // expected-warning{{implicit conversion from 'void (*)(void) __attribute__((cfi_unchecked_callee))' to 'void (*)(void)' discards 'cfi_unchecked_callee' attribute}} |
| void (CFI_UNCHECKED_CALLEE *cfi_unchecked_elem)(void) = arr[1]; |
| |
| int invoke = checked_arg_func(unchecked); // expected-warning{{implicit conversion from 'void (void) __attribute__((cfi_unchecked_callee))' to 'void (*)(void)' discards 'cfi_unchecked_callee' attribute}} |
| } |
| |
| checked_func_t *returning_checked_func() { |
| return unchecked; // expected-warning{{implicit conversion from 'void (void) __attribute__((cfi_unchecked_callee))' to 'void (*)(void)' discards 'cfi_unchecked_callee' attribute}} |
| } |
| |
| void no_args(void) __attribute__((cfi_unchecked_callee(10))); // expected-error{{'cfi_unchecked_callee' attribute takes no arguments}} |
| |
| void Comparisons() { |
| /// Let's be able to compare checked and unchecked pointers without warnings. |
| unchecked == checked_ptr; |
| checked_ptr == unchecked; |
| unchecked == unchecked_ptr; |
| unchecked != checked_ptr; |
| checked_ptr != unchecked; |
| unchecked != unchecked_ptr; |
| |
| (void (*)(void))unchecked == checked_ptr; |
| checked_ptr == (void (*)(void))unchecked; |
| } |