summaryrefslogtreecommitdiffstats
path: root/lib/Sema/SemaDeclAttr.cpp
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2014-08-27 04:59:42 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2014-08-27 04:59:42 +0000
commit2a1084ce0e325230a0f480f2b47ff1128dd98612 (patch)
tree92d1e28fa7c0421db1e7cd2465f10e0d86556e16 /lib/Sema/SemaDeclAttr.cpp
parent104bc91e378515da74d19ed4a4ec5d1268bf99c2 (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.cpp67
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()));
}