// 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; }