Do not issue -Wnullability-completeness for dependent types that are not written as pointer types.

llvm-svn: 303451
This commit is contained in:
Richard Smith 2017-05-19 20:20:13 +00:00
parent d05a006a53
commit 0a12b90c98
5 changed files with 27 additions and 25 deletions

View File

@ -2011,10 +2011,11 @@ public:
Optional<NullabilityKind> getNullability(const ASTContext &context) const;
/// Determine whether the given type can have a nullability
/// specifier applied to it, i.e., if it is any kind of pointer type
/// or a dependent type that could instantiate to any kind of
/// pointer type.
bool canHaveNullability() const;
/// specifier applied to it, i.e., if it is any kind of pointer type.
///
/// \param ResultIfUnknown The value to return if we don't yet know whether
/// this type can have nullability because it is dependent.
bool canHaveNullability(bool ResultIfUnknown = true) const;
/// Retrieve the set of substitutions required when accessing a member
/// of the Objective-C receiver type that is declared in the given context.

View File

@ -3531,7 +3531,7 @@ Optional<NullabilityKind> Type::getNullability(const ASTContext &context) const
} while (true);
}
bool Type::canHaveNullability() const {
bool Type::canHaveNullability(bool ResultIfUnknown) const {
QualType type = getCanonicalTypeInternal();
switch (type->getTypeClass()) {
@ -3559,7 +3559,8 @@ bool Type::canHaveNullability() const {
case Type::SubstTemplateTypeParmPack:
case Type::DependentName:
case Type::DependentTemplateSpecialization:
return true;
case Type::Auto:
return ResultIfUnknown;
// Dependent template specializations can instantiate to pointer
// types unless they're known to be specializations of a class
@ -3571,12 +3572,7 @@ bool Type::canHaveNullability() const {
if (isa<ClassTemplateDecl>(templateDecl))
return false;
}
return true;
// auto is considered dependent when it isn't deduced.
case Type::Auto:
case Type::DeducedTemplateSpecialization:
return !cast<DeducedType>(type.getTypePtr())->isDeduced();
return ResultIfUnknown;
case Type::Builtin:
switch (cast<BuiltinType>(type.getTypePtr())->getKind()) {
@ -3595,7 +3591,7 @@ bool Type::canHaveNullability() const {
case BuiltinType::PseudoObject:
case BuiltinType::UnknownAny:
case BuiltinType::ARCUnbridgedCast:
return true;
return ResultIfUnknown;
case BuiltinType::Void:
case BuiltinType::ObjCId:
@ -3614,6 +3610,7 @@ bool Type::canHaveNullability() const {
case BuiltinType::OMPArraySection:
return false;
}
llvm_unreachable("unknown builtin type");
// Non-pointer types.
case Type::Complex:
@ -3629,6 +3626,7 @@ bool Type::canHaveNullability() const {
case Type::FunctionProto:
case Type::FunctionNoProto:
case Type::Record:
case Type::DeducedTemplateSpecialization:
case Type::Enum:
case Type::InjectedClassName:
case Type::PackExpansion:

View File

@ -3735,16 +3735,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// inner pointers.
complainAboutMissingNullability = CAMN_InnerPointers;
auto isDependentNonPointerType = [](QualType T) -> bool {
// Note: This is intended to be the same check as Type::canHaveNullability
// except with all of the ambiguous cases being treated as 'false' rather
// than 'true'.
return T->isDependentType() && !T->isAnyPointerType() &&
!T->isBlockPointerType() && !T->isMemberPointerType();
};
if (T->canHaveNullability() && !T->getNullability(S.Context) &&
!isDependentNonPointerType(T)) {
if (T->canHaveNullability(/*ResultIfUnknown*/false) &&
!T->getNullability(S.Context)) {
// Note that we allow but don't require nullability on dependent types.
++NumPointersRemaining;
}
@ -3962,7 +3954,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// If the type itself could have nullability but does not, infer pointer
// nullability and perform consistency checking.
if (S.CodeSynthesisContexts.empty()) {
if (T->canHaveNullability() && !T->getNullability(S.Context)) {
if (T->canHaveNullability(/*ResultIfUnknown*/false) &&
!T->getNullability(S.Context)) {
if (isVaList(T)) {
// Record that we've seen a pointer, but do nothing else.
if (NumPointersRemaining > 0)

View File

@ -0,0 +1,4 @@
template<typename T> struct Template final {
int *_Nonnull x;
T y;
};

View File

@ -1,10 +1,12 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -Wno-nullability-declspec %s -verify -Wnullable-to-nonnull-conversion
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -Wno-nullability-declspec %s -verify -Wnullable-to-nonnull-conversion -I%S/Inputs
#if __has_feature(nullability)
#else
# error nullability feature should be defined
#endif
#include "nullability-completeness.h"
typedef decltype(nullptr) nullptr_t;
class X {
@ -130,3 +132,7 @@ void arraysInLambdas() {
withTypedef(nullptr); // expected-warning {{null passed to a callee that requires a non-null argument}}
auto withTypedefBad = [](INTS _Nonnull[2]) {}; // expected-error {{nullability specifier '_Nonnull' cannot be applied to non-pointer type 'INTS' (aka 'int [4]')}}
}
void testNullabilityCompletenessWithTemplate() {
Template<int*> tip;
}