diff options
| author | Richard Smith <richard-llvm@metafoo.co.uk> | 2014-08-27 04:59:42 +0000 |
|---|---|---|
| committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2014-08-27 04:59:42 +0000 |
| commit | 588bd9b7f869578e80c4359694425a5fd20e3ebd (patch) | |
| tree | a128c29aad9b61368c5b0f12d776a2cbb5a29fa6 /clang/lib/Sema | |
| parent | 88d786eab827ca485e31f256e4b5a2cf93fc6b50 (diff) | |
| download | bcm5719-llvm-588bd9b7f869578e80c4359694425a5fd20e3ebd.tar.gz bcm5719-llvm-588bd9b7f869578e80c4359694425a5fd20e3ebd.zip | |
Fix representation of __attribute__((nonnull)) to support correctly modeling
the no-arguments case. Don't expand this to an __attribute__((nonnull(A, B,
C))) attribute, since that does the wrong thing for function templates and
varargs functions.
In passing, fix a grammar error in the diagnostic, a crash if
__attribute__((nonnull(N))) is applied to a varargs function,
a bug where the same null argument could be diagnosed multiple
times if there were multiple nonnull attributes referring to it,
and a bug where nonnull attributes would not be accumulated correctly
across redeclarations.
llvm-svn: 216520
Diffstat (limited to 'clang/lib/Sema')
| -rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 36 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 67 |
2 files changed, 62 insertions, 41 deletions
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 331c5b31a79..c1263d45eb4 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -764,12 +764,26 @@ static void CheckNonNullArgument(Sema &S, static void CheckNonNullArguments(Sema &S, const NamedDecl *FDecl, - const Expr * const *ExprArgs, + ArrayRef<const Expr *> Args, SourceLocation CallSiteLoc) { // Check the attributes attached to the method/function itself. + llvm::SmallBitVector NonNullArgs; for (const auto *NonNull : FDecl->specific_attrs<NonNullAttr>()) { - for (const auto &Val : NonNull->args()) - CheckNonNullArgument(S, ExprArgs[Val], CallSiteLoc); + if (!NonNull->args_size()) { + // Easy case: all pointer arguments are nonnull. + for (const auto *Arg : Args) + if (S.isValidNonNullAttrType(Arg->getType())) + CheckNonNullArgument(S, Arg, CallSiteLoc); + return; + } + + for (unsigned Val : NonNull->args()) { + if (Val >= Args.size()) + continue; + if (NonNullArgs.empty()) + NonNullArgs.resize(Args.size()); + NonNullArgs.set(Val); + } } // Check the attributes on the parameters. @@ -779,13 +793,19 @@ static void CheckNonNullArguments(Sema &S, else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(FDecl)) parms = MD->parameters(); - unsigned argIndex = 0; + unsigned ArgIndex = 0; for (ArrayRef<ParmVarDecl*>::iterator I = parms.begin(), E = parms.end(); - I != E; ++I, ++argIndex) { + I != E; ++I, ++ArgIndex) { const ParmVarDecl *PVD = *I; - if (PVD->hasAttr<NonNullAttr>()) - CheckNonNullArgument(S, ExprArgs[argIndex], CallSiteLoc); + if (PVD->hasAttr<NonNullAttr>() || + (ArgIndex < NonNullArgs.size() && NonNullArgs[ArgIndex])) + CheckNonNullArgument(S, Args[ArgIndex], CallSiteLoc); } + + // In case this is a variadic call, check any remaining arguments. + for (/**/; ArgIndex < NonNullArgs.size(); ++ArgIndex) + if (NonNullArgs[ArgIndex]) + CheckNonNullArgument(S, Args[ArgIndex], CallSiteLoc); } /// Handles the checks for format strings, non-POD arguments to vararg @@ -823,7 +843,7 @@ void Sema::checkCall(NamedDecl *FDecl, ArrayRef<const Expr *> Args, } if (FDecl) { - CheckNonNullArguments(*this, FDecl, Args.data(), Loc); + CheckNonNullArguments(*this, FDecl, Args, Loc); // Type safety checking. for (const auto *I : FDecl->specific_attrs<ArgumentWithTypeTagAttr>()) diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index a1afbdba7aa..7c21206fd4f 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -1125,28 +1125,30 @@ static void handleIBOutletCollection(Sema &S, Decl *D, Attr.getAttributeSpellingListIndex())); } -static void possibleTransparentUnionPointerType(QualType &T) { - if (const RecordType *UT = T->getAsUnionType()) +bool Sema::isValidNonNullAttrType(QualType T) { + T = T.getNonReferenceType(); + + // The nonnull attribute can be applied to a transparent union that + // contains a pointer type. + if (const RecordType *UT = T->getAsUnionType()) { if (UT && UT->getDecl()->hasAttr<TransparentUnionAttr>()) { RecordDecl *UD = UT->getDecl(); for (const auto *I : UD->fields()) { QualType QT = I->getType(); - if (QT->isAnyPointerType() || QT->isBlockPointerType()) { - T = QT; - return; - } + if (QT->isAnyPointerType() || QT->isBlockPointerType()) + return true; } } + } + + return T->isAnyPointerType() || T->isBlockPointerType(); } static bool attrNonNullArgCheck(Sema &S, QualType T, const AttributeList &Attr, SourceRange AttrParmRange, SourceRange NonNullTypeRange, bool isReturnValue = false) { - T = T.getNonReferenceType(); - possibleTransparentUnionPointerType(T); - - if (!T->isAnyPointerType() && !T->isBlockPointerType()) { + if (!S.isValidNonNullAttrType(T)) { S.Diag(Attr.getLoc(), isReturnValue ? diag::warn_attribute_return_pointers_only : diag::warn_attribute_pointers_only) @@ -1158,14 +1160,15 @@ static bool attrNonNullArgCheck(Sema &S, QualType T, const AttributeList &Attr, static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) { SmallVector<unsigned, 8> NonNullArgs; - for (unsigned i = 0; i < Attr.getNumArgs(); ++i) { - Expr *Ex = Attr.getArgAsExpr(i); + for (unsigned I = 0; I < Attr.getNumArgs(); ++I) { + Expr *Ex = Attr.getArgAsExpr(I); uint64_t Idx; - if (!checkFunctionOrMethodParameterIndex(S, D, Attr, i + 1, Ex, Idx)) + if (!checkFunctionOrMethodParameterIndex(S, D, Attr, I + 1, Ex, Idx)) return; // Is the function argument a pointer type? - if (!attrNonNullArgCheck(S, getFunctionOrMethodParamType(D, Idx), Attr, + if (Idx < getFunctionOrMethodNumParams(D) && + !attrNonNullArgCheck(S, getFunctionOrMethodParamType(D, Idx), Attr, Ex->getSourceRange(), getFunctionOrMethodParamRange(D, Idx))) continue; @@ -1174,30 +1177,28 @@ static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) { } // If no arguments were specified to __attribute__((nonnull)) then all pointer - // arguments have a nonnull attribute. - if (NonNullArgs.empty()) { - for (unsigned i = 0, e = getFunctionOrMethodNumParams(D); i != e; ++i) { - QualType T = getFunctionOrMethodParamType(D, i).getNonReferenceType(); - possibleTransparentUnionPointerType(T); - if (T->isAnyPointerType() || T->isBlockPointerType()) - NonNullArgs.push_back(i); + // arguments have a nonnull attribute; warn if there aren't any. Skip this + // check if the attribute came from a macro expansion or a template + // instantiation. + if (NonNullArgs.empty() && Attr.getLoc().isFileID() && + S.ActiveTemplateInstantiations.empty()) { + bool AnyPointers = isFunctionOrMethodVariadic(D); + for (unsigned I = 0, E = getFunctionOrMethodNumParams(D); + I != E && !AnyPointers; ++I) { + QualType T = getFunctionOrMethodParamType(D, I); + if (T->isDependentType() || S.isValidNonNullAttrType(T)) + AnyPointers = true; } - // No pointer arguments? - if (NonNullArgs.empty()) { - // Warn the trivial case only if attribute is not coming from a - // macro instantiation. - if (Attr.getLoc().isFileID()) - S.Diag(Attr.getLoc(), diag::warn_attribute_nonnull_no_pointers); - return; - } + if (!AnyPointers) + S.Diag(Attr.getLoc(), diag::warn_attribute_nonnull_no_pointers); } - unsigned *start = &NonNullArgs[0]; - unsigned size = NonNullArgs.size(); - llvm::array_pod_sort(start, start + size); + unsigned *Start = NonNullArgs.data(); + unsigned Size = NonNullArgs.size(); + llvm::array_pod_sort(Start, Start + Size); D->addAttr(::new (S.Context) - NonNullAttr(Attr.getRange(), S.Context, start, size, + NonNullAttr(Attr.getRange(), S.Context, Start, Size, Attr.getAttributeSpellingListIndex())); } |

