jordan_rose created this revision. jordan_rose added reviewers: doug.gregor, rsmith. jordan_rose added a subscriber: cfe-commits. jordan_rose set the repository for this revision to rL LLVM. jordan_rose added dependencies: D26226: Don't require nullability on template parameters in typedefs., D25850: Accept nullability annotations (_Nullable) on array parameters.
There are many non-portable typedefs, but va_list is one that nobody ever thinks of as a pointer or an array. (When's the last time you saw someone check for a NULL va_list?) Make an exception for this one special type. (Is this the best way to do this?) Part of rdar://problem/25846421. Depends on https://reviews.llvm.org/D26226 and https://reviews.llvm.org/D25850. Repository: rL LLVM https://reviews.llvm.org/D26227 Files: lib/Sema/SemaType.cpp test/SemaObjCXX/Inputs/nullability-consistency-arrays.h Index: test/SemaObjCXX/Inputs/nullability-consistency-arrays.h =================================================================== --- test/SemaObjCXX/Inputs/nullability-consistency-arrays.h +++ test/SemaObjCXX/Inputs/nullability-consistency-arrays.h @@ -1,3 +1,5 @@ +#include <stdarg.h> + void firstThingInTheFileThatNeedsNullabilityIsAnArray(int ints[]); #if ARRAYS_CHECKED // expected-warning@-2 {{array parameter is missing a nullability type specifier (_Nonnull, _Nullable, or _Null_unspecified)}} @@ -33,6 +35,26 @@ void * _Nullable ptrs[_Nonnull], void * _Nullable * _Nullable nestedPtrs[_Nonnull]); +void testVAList(va_list ok); // no warning + +#if __cplusplus +// Carefully construct a test case such that if a platform's va_list is an array +// or pointer type, it gets tested, but otherwise it does not. +template<class T, class F> +struct pointer_like_or { typedef F type; }; +template<class T, class F> +struct pointer_like_or<T*, F> { typedef T *type; }; +template<class T, class F> +struct pointer_like_or<T* const, F> { typedef T * const type; }; +template<class T, class F> +struct pointer_like_or<T[], F> { typedef T type[]; }; +template<class T, class F, unsigned size> +struct pointer_like_or<T[size], F> { typedef T type[size]; }; + +void testVAListWithNullability( + pointer_like_or<va_list, void*>::type _Nonnull x); // no errors +#endif + void nestedArrays(int x[5][1]) {} #if ARRAYS_CHECKED // expected-warning@-2 {{array parameter is missing a nullability type specifier (_Nonnull, _Nullable, or _Null_unspecified)}} Index: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -3894,8 +3894,22 @@ attr->setUsedAsTypeAttr(); } } + + auto isVaList = [&S](QualType T) -> bool { + auto *typedefTy = T->getAs<TypedefType>(); + if (!typedefTy) + return false; + TypedefDecl *vaListTypedef = S.Context.getBuiltinVaListDecl(); + do { + if (typedefTy->getDecl() == vaListTypedef) + return true; + typedefTy = typedefTy->desugar()->getAs<TypedefType>(); + } while (typedefTy); + return false; + }; + if (complainAboutMissingNullability == CAMN_Yes && - T->isArrayType() && !T->getNullability(S.Context) && + T->isArrayType() && !T->getNullability(S.Context) && !isVaList(T) && D.isPrototypeContext() && !hasOuterPointerLikeChunk(D, D.getNumTypeObjects())) { checkNullabilityConsistency(S, SimplePointerKind::Array,
Index: test/SemaObjCXX/Inputs/nullability-consistency-arrays.h =================================================================== --- test/SemaObjCXX/Inputs/nullability-consistency-arrays.h +++ test/SemaObjCXX/Inputs/nullability-consistency-arrays.h @@ -1,3 +1,5 @@ +#include <stdarg.h> + void firstThingInTheFileThatNeedsNullabilityIsAnArray(int ints[]); #if ARRAYS_CHECKED // expected-warning@-2 {{array parameter is missing a nullability type specifier (_Nonnull, _Nullable, or _Null_unspecified)}} @@ -33,6 +35,26 @@ void * _Nullable ptrs[_Nonnull], void * _Nullable * _Nullable nestedPtrs[_Nonnull]); +void testVAList(va_list ok); // no warning + +#if __cplusplus +// Carefully construct a test case such that if a platform's va_list is an array +// or pointer type, it gets tested, but otherwise it does not. +template<class T, class F> +struct pointer_like_or { typedef F type; }; +template<class T, class F> +struct pointer_like_or<T*, F> { typedef T *type; }; +template<class T, class F> +struct pointer_like_or<T* const, F> { typedef T * const type; }; +template<class T, class F> +struct pointer_like_or<T[], F> { typedef T type[]; }; +template<class T, class F, unsigned size> +struct pointer_like_or<T[size], F> { typedef T type[size]; }; + +void testVAListWithNullability( + pointer_like_or<va_list, void*>::type _Nonnull x); // no errors +#endif + void nestedArrays(int x[5][1]) {} #if ARRAYS_CHECKED // expected-warning@-2 {{array parameter is missing a nullability type specifier (_Nonnull, _Nullable, or _Null_unspecified)}} Index: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -3894,8 +3894,22 @@ attr->setUsedAsTypeAttr(); } } + + auto isVaList = [&S](QualType T) -> bool { + auto *typedefTy = T->getAs<TypedefType>(); + if (!typedefTy) + return false; + TypedefDecl *vaListTypedef = S.Context.getBuiltinVaListDecl(); + do { + if (typedefTy->getDecl() == vaListTypedef) + return true; + typedefTy = typedefTy->desugar()->getAs<TypedefType>(); + } while (typedefTy); + return false; + }; + if (complainAboutMissingNullability == CAMN_Yes && - T->isArrayType() && !T->getNullability(S.Context) && + T->isArrayType() && !T->getNullability(S.Context) && !isVaList(T) && D.isPrototypeContext() && !hasOuterPointerLikeChunk(D, D.getNumTypeObjects())) { checkNullabilityConsistency(S, SimplePointerKind::Array,
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits