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 | 2a1084ce0e325230a0f480f2b47ff1128dd98612 (patch) | |
tree | 92d1e28fa7c0421db1e7cd2465f10e0d86556e16 /lib/Sema/SemaDeclAttr.cpp | |
parent | 104bc91e378515da74d19ed4a4ec5d1268bf99c2 (diff) |
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.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@216520 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaDeclAttr.cpp')
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 67 |
1 files changed, 34 insertions, 33 deletions
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index a1afbdba7a..7c21206fd4 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/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())); } |