Introduce type nullability specifiers for C/C++.
Introduces the type specifiers __nonnull, __nullable, and
__null_unspecified that describe the nullability of the pointer type
to which the specifier appertains. Nullability type specifiers improve
on the existing nonnull attributes in a few ways:
- They apply to types, so one can represent a pointer to a non-null
pointer, use them in function pointer types, etc.
- As type specifiers, they are syntactically more lightweight than
__attribute__s or [[attribute]]s.
- They can express both the notion of 'should never be null' and
also 'it makes sense for this to be null', and therefore can more
easily catch errors of omission where one forgot to annotate the
nullability of a particular pointer (this will come in a subsequent
patch).
Nullability type specifiers are maintained as type sugar, and
therefore have no effect on mangling, encoding, overloading,
etc. Nonetheless, they will be used for warnings about, e.g., passing
'null' to a method that does not accept it.
This is the C/C++ part of rdar://problem/18868820.
llvm-svn: 240146
2015-06-20 01:51:05 +08:00
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -Wno-nullability-declspec %s -verify
typedef decltype ( nullptr ) nullptr_t ;
class X {
} ;
// Nullability applies to all pointer types.
typedef int ( X : : * __nonnull member_function_type_1 ) ( int ) ;
typedef int X : : * __nonnull member_data_type_1 ;
typedef nullptr_t __nonnull nonnull_nullptr_t ; // expected-error{{nullability specifier '__nonnull' cannot be applied to non-pointer type 'nullptr_t'}}
// Nullability can move into member pointers (this is suppressing a warning).
typedef __nonnull int ( X : : * member_function_type_2 ) ( int ) ;
typedef int ( X : : * __nonnull member_function_type_3 ) ( int ) ;
typedef __nonnull int X : : * member_data_type_2 ;
// Adding non-null via a template.
template < typename T >
struct AddNonNull {
typedef __nonnull T type ; // expected-error{{nullability specifier '__nonnull' cannot be applied to non-pointer type 'int'}}
// expected-error@-1{{nullability specifier '__nonnull' cannot be applied to non-pointer type 'nullptr_t'}}
} ;
typedef AddNonNull < int * > : : type nonnull_int_ptr_1 ;
typedef AddNonNull < int * __nullable > : : type nonnull_int_ptr_2 ; // FIXME: check that it was overridden
typedef AddNonNull < nullptr_t > : : type nonnull_int_ptr_3 ; // expected-note{{in instantiation of template class}}
typedef AddNonNull < int > : : type nonnull_non_pointer_1 ; // expected-note{{in instantiation of template class 'AddNonNull<int>' requested here}}
// Non-null checking within a template.
template < typename T >
struct AddNonNull2 {
typedef __nonnull AddNonNull < T > invalid1 ; // expected-error{{nullability specifier '__nonnull' cannot be applied to non-pointer type 'AddNonNull<T>'}}
typedef __nonnull AddNonNull2 invalid2 ; // expected-error{{nullability specifier '__nonnull' cannot be applied to non-pointer type 'AddNonNull2<T>'}}
typedef __nonnull AddNonNull2 < T > invalid3 ; // expected-error{{nullability specifier '__nonnull' cannot be applied to non-pointer type 'AddNonNull2<T>'}}
typedef __nonnull typename AddNonNull < T > : : type okay1 ;
// Don't move past a dependent type even if we know that nullability
// cannot apply to that specific dependent type.
typedef __nonnull AddNonNull < T > ( * invalid4 ) ; // expected-error{{nullability specifier '__nonnull' cannot be applied to non-pointer type 'AddNonNull<T>'}}
} ;
2015-06-20 02:13:19 +08:00
// Check passing null to a __nonnull argument.
void ( * accepts_nonnull_1 ) ( __nonnull int * ptr ) ;
void ( * & accepts_nonnull_2 ) ( __nonnull int * ptr ) = accepts_nonnull_1 ;
void ( X : : * accepts_nonnull_3 ) ( __nonnull int * ptr ) ;
void accepts_nonnull_4 ( __nonnull int * ptr ) ;
void ( & accepts_nonnull_5 ) ( __nonnull int * ptr ) = accepts_nonnull_4 ;
void test_accepts_nonnull_null_pointer_literal ( X * x ) {
accepts_nonnull_1 ( 0 ) ; // expected-warning{{null passed to a callee that requires a non-null argument}}
accepts_nonnull_2 ( 0 ) ; // expected-warning{{null passed to a callee that requires a non-null argument}}
( x - > * accepts_nonnull_3 ) ( 0 ) ; // expected-warning{{null passed to a callee that requires a non-null argument}}
accepts_nonnull_4 ( 0 ) ; // expected-warning{{null passed to a callee that requires a non-null argument}}
accepts_nonnull_5 ( 0 ) ; // expected-warning{{null passed to a callee that requires a non-null argument}}
}
template < void FP ( __nonnull int * ) >
void test_accepts_nonnull_null_pointer_literal_template ( ) {
FP ( 0 ) ; // expected-warning{{null passed to a callee that requires a non-null argument}}
}
template void test_accepts_nonnull_null_pointer_literal_template < & accepts_nonnull_4 > ( ) ; // expected-note{{instantiation of function template specialization}}