diff options
author | Nuno Lopes <nunoplopes@sapo.pt> | 2012-05-24 00:22:00 +0000 |
---|---|---|
committer | Nuno Lopes <nunoplopes@sapo.pt> | 2012-05-24 00:22:00 +0000 |
commit | 587de5be6bc8b9d046015b20079d45ac4b98bc14 (patch) | |
tree | 97521b9839288adb06fbc81639a67a9852531844 /lib/Sema/SemaDeclAttr.cpp | |
parent | 042b91d53980048619d1e61431387ebe84d384f4 (diff) |
implement Sema support for the alloc_size attribute
Portions of this patch by Xi Wang. Reviewed by Jordy Rose. Thank you both.
Codegen support will follow soon.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@157360 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaDeclAttr.cpp')
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index ff25645707..bc1c3afbe2 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -922,6 +922,81 @@ static void possibleTransparentUnionPointerType(QualType &T) { } } +static void handleAllocSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) { + if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) + return; + + // In C++ the implicit 'this' function parameter also counts, and they are + // counted from one. + bool HasImplicitThisParam = isInstanceMethod(D); + unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam; + + SmallVector<unsigned, 8> SizeArgs; + + for (AttributeList::arg_iterator I = Attr.arg_begin(), + E = Attr.arg_end(); I!=E; ++I) { + // The argument must be an integer constant expression. + Expr *Ex = *I; + llvm::APSInt ArgNum; + if (Ex->isTypeDependent() || Ex->isValueDependent() || + !Ex->isIntegerConstantExpr(ArgNum, S.Context)) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) + << "alloc_size" << Ex->getSourceRange(); + return; + } + + uint64_t x = ArgNum.getZExtValue(); + + if (x < 1 || x > NumArgs) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds) + << "alloc_size" << I.getArgNum() << Ex->getSourceRange(); + return; + } + + --x; + if (HasImplicitThisParam) { + if (x == 0) { + S.Diag(Attr.getLoc(), + diag::err_attribute_invalid_implicit_this_argument) + << "alloc_size" << Ex->getSourceRange(); + return; + } + --x; + } + + // check if the function argument is of an integer type + QualType T = getFunctionOrMethodArgType(D, x).getNonReferenceType(); + if (!T->isIntegerType()) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) + << "alloc_size" << Ex->getSourceRange(); + return; + } + + // check if the argument is a duplicate + SmallVectorImpl<unsigned>::iterator Pos; + Pos = std::find(SizeArgs.begin(), SizeArgs.end(), x); + if (Pos != SizeArgs.end()) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_duplicate) + << "alloc_size" << I.getArgNum() << Ex->getSourceRange(); + return; + } + + SizeArgs.push_back(x); + } + + // check if the function returns a pointer + if (!getFunctionType(D)->getResultType()->isAnyPointerType()) { + S.Diag(Attr.getLoc(), diag::warn_ns_attribute_wrong_return_type) + << "alloc_size" << 0 /*function*/<< 1 /*pointer*/ << D->getSourceRange(); + } + + unsigned size = SizeArgs.size(); + unsigned* start = &SizeArgs[0]; + llvm::array_pod_sort(start, start + size); + D->addAttr(::new (S.Context) AllocSizeAttr(Attr.getRange(), S.Context, start, + size)); +} + static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) { // GCC ignores the nonnull attribute on K&R style function prototypes, so we // ignore it as well @@ -3844,6 +3919,7 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D, break; case AttributeList::AT_alias: handleAliasAttr (S, D, Attr); break; case AttributeList::AT_aligned: handleAlignedAttr (S, D, Attr); break; + case AttributeList::AT_alloc_size: handleAllocSizeAttr (S, D, Attr); break; case AttributeList::AT_always_inline: handleAlwaysInlineAttr (S, D, Attr); break; case AttributeList::AT_analyzer_noreturn: |