2008-06-27 02:38:35 +08:00
|
|
|
//===--- SemaDeclAttr.cpp - Declaration Attribute Handling ----------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements decl-related attribute processing.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "Sema.h"
|
|
|
|
#include "clang/AST/ASTContext.h"
|
2008-08-11 14:23:49 +08:00
|
|
|
#include "clang/AST/DeclObjC.h"
|
|
|
|
#include "clang/AST/Expr.h"
|
2008-06-28 06:18:37 +08:00
|
|
|
#include "clang/Basic/TargetInfo.h"
|
2008-08-11 11:27:53 +08:00
|
|
|
#include "clang/Parse/DeclSpec.h"
|
2009-08-11 03:03:04 +08:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2008-06-27 02:38:35 +08:00
|
|
|
using namespace clang;
|
|
|
|
|
2008-06-29 08:16:31 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Helper functions
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-08-15 04:49:40 +08:00
|
|
|
static const FunctionType *getFunctionType(const Decl *d,
|
|
|
|
bool blocksToo = true) {
|
2008-06-27 02:38:35 +08:00
|
|
|
QualType Ty;
|
2009-08-15 04:49:40 +08:00
|
|
|
if (const ValueDecl *decl = dyn_cast<ValueDecl>(d))
|
2008-06-27 02:38:35 +08:00
|
|
|
Ty = decl->getType();
|
2009-08-15 04:49:40 +08:00
|
|
|
else if (const FieldDecl *decl = dyn_cast<FieldDecl>(d))
|
2008-06-27 02:38:35 +08:00
|
|
|
Ty = decl->getType();
|
2009-08-15 04:49:40 +08:00
|
|
|
else if (const TypedefDecl* decl = dyn_cast<TypedefDecl>(d))
|
2008-06-27 02:38:35 +08:00
|
|
|
Ty = decl->getUnderlyingType();
|
|
|
|
else
|
|
|
|
return 0;
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-06-27 02:38:35 +08:00
|
|
|
if (Ty->isFunctionPointerType())
|
2009-07-30 05:53:49 +08:00
|
|
|
Ty = Ty->getAs<PointerType>()->getPointeeType();
|
2009-05-19 01:39:25 +08:00
|
|
|
else if (blocksToo && Ty->isBlockPointerType())
|
2009-07-30 05:53:49 +08:00
|
|
|
Ty = Ty->getAs<BlockPointerType>()->getPointeeType();
|
2008-10-19 10:04:16 +08:00
|
|
|
|
|
|
|
return Ty->getAsFunctionType();
|
2008-06-27 02:38:35 +08:00
|
|
|
}
|
|
|
|
|
2008-09-26 12:12:28 +08:00
|
|
|
// FIXME: We should provide an abstraction around a method or function
|
|
|
|
// to provide the following bits of information.
|
|
|
|
|
2009-08-15 04:49:40 +08:00
|
|
|
/// isFunctionOrMethod - Return true if the given decl has function
|
|
|
|
/// type (function or function-typed variable).
|
|
|
|
static bool isFunction(const Decl *d) {
|
|
|
|
return getFunctionType(d, false) != NULL;
|
|
|
|
}
|
|
|
|
|
2008-10-19 10:04:16 +08:00
|
|
|
/// isFunctionOrMethod - Return true if the given decl has function
|
|
|
|
/// type (function or function-typed variable) or an Objective-C
|
|
|
|
/// method.
|
2009-08-15 04:49:40 +08:00
|
|
|
static bool isFunctionOrMethod(const Decl *d) {
|
|
|
|
return isFunction(d)|| isa<ObjCMethodDecl>(d);
|
2008-10-19 10:04:16 +08:00
|
|
|
}
|
2008-09-26 12:12:28 +08:00
|
|
|
|
2009-05-16 07:15:03 +08:00
|
|
|
/// isFunctionOrMethodOrBlock - Return true if the given decl has function
|
|
|
|
/// type (function or function-typed variable) or an Objective-C
|
|
|
|
/// method or a block.
|
2009-08-15 04:49:40 +08:00
|
|
|
static bool isFunctionOrMethodOrBlock(const Decl *d) {
|
2009-05-16 07:15:03 +08:00
|
|
|
if (isFunctionOrMethod(d))
|
|
|
|
return true;
|
|
|
|
// check for block is more involved.
|
|
|
|
if (const VarDecl *V = dyn_cast<VarDecl>(d)) {
|
|
|
|
QualType Ty = V->getType();
|
|
|
|
return Ty->isBlockPointerType();
|
|
|
|
}
|
2009-05-20 01:08:59 +08:00
|
|
|
return isa<BlockDecl>(d);
|
2009-05-16 07:15:03 +08:00
|
|
|
}
|
|
|
|
|
2008-10-19 10:04:16 +08:00
|
|
|
/// hasFunctionProto - Return true if the given decl has a argument
|
|
|
|
/// information. This decl should have already passed
|
2009-05-16 07:15:03 +08:00
|
|
|
/// isFunctionOrMethod or isFunctionOrMethodOrBlock.
|
2009-08-15 04:49:40 +08:00
|
|
|
static bool hasFunctionProto(const Decl *d) {
|
2009-05-16 07:15:03 +08:00
|
|
|
if (const FunctionType *FnTy = getFunctionType(d))
|
2009-02-27 07:50:07 +08:00
|
|
|
return isa<FunctionProtoType>(FnTy);
|
2009-05-16 07:15:03 +08:00
|
|
|
else {
|
2009-05-20 01:08:59 +08:00
|
|
|
assert(isa<ObjCMethodDecl>(d) || isa<BlockDecl>(d));
|
2008-10-19 10:04:16 +08:00
|
|
|
return true;
|
|
|
|
}
|
2008-09-26 12:12:28 +08:00
|
|
|
}
|
|
|
|
|
2008-10-19 10:04:16 +08:00
|
|
|
/// getFunctionOrMethodNumArgs - Return number of function or method
|
|
|
|
/// arguments. It is an error to call this on a K&R function (use
|
|
|
|
/// hasFunctionProto first).
|
2009-08-15 04:49:40 +08:00
|
|
|
static unsigned getFunctionOrMethodNumArgs(const Decl *d) {
|
2009-02-21 02:43:26 +08:00
|
|
|
if (const FunctionType *FnTy = getFunctionType(d))
|
2009-02-27 07:50:07 +08:00
|
|
|
return cast<FunctionProtoType>(FnTy)->getNumArgs();
|
2009-05-20 01:08:59 +08:00
|
|
|
if (const BlockDecl *BD = dyn_cast<BlockDecl>(d))
|
|
|
|
return BD->getNumParams();
|
2009-02-21 02:43:26 +08:00
|
|
|
return cast<ObjCMethodDecl>(d)->param_size();
|
2008-09-26 12:12:28 +08:00
|
|
|
}
|
|
|
|
|
2009-08-15 04:49:40 +08:00
|
|
|
static QualType getFunctionOrMethodArgType(const Decl *d, unsigned Idx) {
|
2009-02-21 02:43:26 +08:00
|
|
|
if (const FunctionType *FnTy = getFunctionType(d))
|
2009-02-27 07:50:07 +08:00
|
|
|
return cast<FunctionProtoType>(FnTy)->getArgType(Idx);
|
2009-05-20 01:08:59 +08:00
|
|
|
if (const BlockDecl *BD = dyn_cast<BlockDecl>(d))
|
|
|
|
return BD->getParamDecl(Idx)->getType();
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-02-21 02:43:26 +08:00
|
|
|
return cast<ObjCMethodDecl>(d)->param_begin()[Idx]->getType();
|
2008-09-26 12:12:28 +08:00
|
|
|
}
|
|
|
|
|
2009-08-15 04:49:40 +08:00
|
|
|
static QualType getFunctionOrMethodResultType(const Decl *d) {
|
2009-05-21 01:41:43 +08:00
|
|
|
if (const FunctionType *FnTy = getFunctionType(d))
|
|
|
|
return cast<FunctionProtoType>(FnTy)->getResultType();
|
|
|
|
return cast<ObjCMethodDecl>(d)->getResultType();
|
|
|
|
}
|
|
|
|
|
2009-08-15 04:49:40 +08:00
|
|
|
static bool isFunctionOrMethodVariadic(const Decl *d) {
|
2008-10-19 10:04:16 +08:00
|
|
|
if (const FunctionType *FnTy = getFunctionType(d)) {
|
2009-02-27 07:50:07 +08:00
|
|
|
const FunctionProtoType *proto = cast<FunctionProtoType>(FnTy);
|
2008-09-26 12:12:28 +08:00
|
|
|
return proto->isVariadic();
|
2009-05-20 01:08:59 +08:00
|
|
|
} else if (const BlockDecl *BD = dyn_cast<BlockDecl>(d))
|
|
|
|
return BD->IsVariadic();
|
|
|
|
else {
|
2008-09-26 12:12:28 +08:00
|
|
|
return cast<ObjCMethodDecl>(d)->isVariadic();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-27 02:38:35 +08:00
|
|
|
static inline bool isNSStringType(QualType T, ASTContext &Ctx) {
|
2009-07-11 07:34:53 +08:00
|
|
|
const ObjCObjectPointerType *PT = T->getAsObjCObjectPointerType();
|
2008-07-27 06:17:49 +08:00
|
|
|
if (!PT)
|
2008-06-27 02:38:35 +08:00
|
|
|
return false;
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-07-27 06:17:49 +08:00
|
|
|
const ObjCInterfaceType *ClsT =PT->getPointeeType()->getAsObjCInterfaceType();
|
2008-06-27 02:38:35 +08:00
|
|
|
if (!ClsT)
|
|
|
|
return false;
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-06-27 02:38:35 +08:00
|
|
|
IdentifierInfo* ClsName = ClsT->getDecl()->getIdentifier();
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-06-27 02:38:35 +08:00
|
|
|
// FIXME: Should we walk the chain of classes?
|
|
|
|
return ClsName == &Ctx.Idents.get("NSString") ||
|
|
|
|
ClsName == &Ctx.Idents.get("NSMutableString");
|
|
|
|
}
|
|
|
|
|
2008-09-26 11:32:58 +08:00
|
|
|
static inline bool isCFStringType(QualType T, ASTContext &Ctx) {
|
2009-07-30 05:53:49 +08:00
|
|
|
const PointerType *PT = T->getAs<PointerType>();
|
2008-09-26 11:32:58 +08:00
|
|
|
if (!PT)
|
|
|
|
return false;
|
|
|
|
|
2009-07-30 05:53:49 +08:00
|
|
|
const RecordType *RT = PT->getPointeeType()->getAs<RecordType>();
|
2008-09-26 11:32:58 +08:00
|
|
|
if (!RT)
|
|
|
|
return false;
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-09-26 11:32:58 +08:00
|
|
|
const RecordDecl *RD = RT->getDecl();
|
|
|
|
if (RD->getTagKind() != TagDecl::TK_struct)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return RD->getIdentifier() == &Ctx.Idents.get("__CFString");
|
|
|
|
}
|
|
|
|
|
2008-06-29 08:16:31 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Attribute Implementations
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2008-08-01 06:40:48 +08:00
|
|
|
// FIXME: All this manual attribute parsing code is gross. At the
|
|
|
|
// least add some helper functions to check most argument patterns (#
|
|
|
|
// and types of args).
|
|
|
|
|
2009-07-25 03:02:52 +08:00
|
|
|
static void HandleExtVectorTypeAttr(Scope *scope, Decl *d,
|
2009-06-18 05:51:59 +08:00
|
|
|
const AttributeList &Attr, Sema &S) {
|
2008-06-29 07:36:30 +08:00
|
|
|
TypedefDecl *tDecl = dyn_cast<TypedefDecl>(d);
|
|
|
|
if (tDecl == 0) {
|
2008-06-29 08:43:07 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_typecheck_ext_vector_not_typedef);
|
2008-06-29 07:36:30 +08:00
|
|
|
return;
|
2008-06-27 02:38:35 +08:00
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-06-27 02:38:35 +08:00
|
|
|
QualType curType = tDecl->getUnderlyingType();
|
2009-06-18 05:51:59 +08:00
|
|
|
|
|
|
|
Expr *sizeExpr;
|
|
|
|
|
|
|
|
// Special case where the argument is a template id.
|
|
|
|
if (Attr.getParameterName()) {
|
|
|
|
sizeExpr = S.ActOnDeclarationNameExpr(scope, Attr.getLoc(),
|
|
|
|
Attr.getParameterName(),
|
|
|
|
false, 0, false).takeAs<Expr>();
|
|
|
|
} else {
|
|
|
|
// check the attribute arguments.
|
|
|
|
if (Attr.getNumArgs() != 1) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
sizeExpr = static_cast<Expr *>(Attr.getArg(0));
|
2008-06-27 02:38:35 +08:00
|
|
|
}
|
2009-06-18 05:51:59 +08:00
|
|
|
|
|
|
|
// Instantiate/Install the vector type, and let Sema build the type for us.
|
|
|
|
// This will run the reguired checks.
|
|
|
|
QualType T = S.BuildExtVectorType(curType, S.Owned(sizeExpr), Attr.getLoc());
|
|
|
|
if (!T.isNull()) {
|
|
|
|
tDecl->setUnderlyingType(T);
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-06-18 05:51:59 +08:00
|
|
|
// Remember this typedef decl, we will need it later for diagnostics.
|
|
|
|
S.ExtVectorDecls.push_back(tDecl);
|
2008-06-27 02:38:35 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-29 07:48:25 +08:00
|
|
|
|
2009-07-25 03:02:52 +08:00
|
|
|
/// HandleVectorSizeAttribute - this attribute is only applicable to integral
|
|
|
|
/// and float scalars, although arrays, pointers, and function return values are
|
|
|
|
/// allowed in conjunction with this construct. Aggregates with this attribute
|
|
|
|
/// are invalid, even if they are of the same size as a corresponding scalar.
|
|
|
|
/// The raw attribute should contain precisely 1 argument, the vector size for
|
|
|
|
/// the variable, measured in bytes. If curType and rawAttr are well formed,
|
|
|
|
/// this routine will return a new vector type.
|
2008-06-29 08:43:07 +08:00
|
|
|
static void HandleVectorSizeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
|
2008-06-29 07:48:25 +08:00
|
|
|
QualType CurType;
|
|
|
|
if (ValueDecl *VD = dyn_cast<ValueDecl>(D))
|
|
|
|
CurType = VD->getType();
|
|
|
|
else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D))
|
|
|
|
CurType = TD->getUnderlyingType();
|
|
|
|
else {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(D->getLocation(), diag::err_attr_wrong_decl)
|
|
|
|
<< "vector_size" << SourceRange(Attr.getLoc(), Attr.getLoc());
|
2008-06-29 07:48:25 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-06-29 07:48:25 +08:00
|
|
|
// Check the attribute arugments.
|
2008-06-29 07:36:30 +08:00
|
|
|
if (Attr.getNumArgs() != 1) {
|
2008-11-19 16:23:25 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
|
2008-06-29 07:48:25 +08:00
|
|
|
return;
|
2008-06-27 02:38:35 +08:00
|
|
|
}
|
2008-06-29 07:36:30 +08:00
|
|
|
Expr *sizeExpr = static_cast<Expr *>(Attr.getArg(0));
|
2008-06-27 02:38:35 +08:00
|
|
|
llvm::APSInt vecSize(32);
|
2008-06-29 08:43:07 +08:00
|
|
|
if (!sizeExpr->isIntegerConstantExpr(vecSize, S.Context)) {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
|
|
|
|
<< "vector_size" << sizeExpr->getSourceRange();
|
2008-06-29 07:48:25 +08:00
|
|
|
return;
|
2008-06-27 02:38:35 +08:00
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
// navigate to the base type - we need to provide for vector pointers, vector
|
|
|
|
// arrays, and functions returning vectors.
|
2008-07-27 06:17:49 +08:00
|
|
|
if (CurType->isPointerType() || CurType->isArrayType() ||
|
|
|
|
CurType->isFunctionType()) {
|
2009-05-13 12:00:12 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_unsupported_vector_size) << CurType;
|
|
|
|
return;
|
2008-06-27 02:38:35 +08:00
|
|
|
/* FIXME: rebuild the type from the inside out, vectorizing the inner type.
|
|
|
|
do {
|
|
|
|
if (PointerType *PT = dyn_cast<PointerType>(canonType))
|
|
|
|
canonType = PT->getPointeeType().getTypePtr();
|
|
|
|
else if (ArrayType *AT = dyn_cast<ArrayType>(canonType))
|
|
|
|
canonType = AT->getElementType().getTypePtr();
|
|
|
|
else if (FunctionType *FT = dyn_cast<FunctionType>(canonType))
|
|
|
|
canonType = FT->getResultType().getTypePtr();
|
|
|
|
} while (canonType->isPointerType() || canonType->isArrayType() ||
|
|
|
|
canonType->isFunctionType());
|
|
|
|
*/
|
|
|
|
}
|
2009-05-13 13:13:44 +08:00
|
|
|
// the base type must be integer or float, and can't already be a vector.
|
|
|
|
if (CurType->isVectorType() ||
|
|
|
|
(!CurType->isIntegerType() && !CurType->isRealFloatingType())) {
|
2008-11-24 14:25:27 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_invalid_vector_type) << CurType;
|
2008-06-29 07:48:25 +08:00
|
|
|
return;
|
2008-06-27 02:38:35 +08:00
|
|
|
}
|
2008-06-29 08:43:07 +08:00
|
|
|
unsigned typeSize = static_cast<unsigned>(S.Context.getTypeSize(CurType));
|
2008-06-27 02:38:35 +08:00
|
|
|
// vecSize is specified in bytes - convert to bits.
|
2009-07-25 03:02:52 +08:00
|
|
|
unsigned vectorSize = static_cast<unsigned>(vecSize.getZExtValue() * 8);
|
|
|
|
|
2008-06-27 02:38:35 +08:00
|
|
|
// the vector size needs to be an integral multiple of the type size.
|
|
|
|
if (vectorSize % typeSize) {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_invalid_size)
|
|
|
|
<< sizeExpr->getSourceRange();
|
2008-06-29 07:48:25 +08:00
|
|
|
return;
|
2008-06-27 02:38:35 +08:00
|
|
|
}
|
|
|
|
if (vectorSize == 0) {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_zero_size)
|
|
|
|
<< sizeExpr->getSourceRange();
|
2008-06-29 07:48:25 +08:00
|
|
|
return;
|
2008-06-27 02:38:35 +08:00
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-06-29 07:48:25 +08:00
|
|
|
// Success! Instantiate the vector type, the number of elements is > 0, and
|
|
|
|
// not required to be a power of 2, unlike GCC.
|
2008-06-29 08:43:07 +08:00
|
|
|
CurType = S.Context.getVectorType(CurType, vectorSize/typeSize);
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-06-29 07:48:25 +08:00
|
|
|
if (ValueDecl *VD = dyn_cast<ValueDecl>(D))
|
|
|
|
VD->setType(CurType);
|
2009-07-25 03:02:52 +08:00
|
|
|
else
|
2008-06-29 07:48:25 +08:00
|
|
|
cast<TypedefDecl>(D)->setUnderlyingType(CurType);
|
2008-06-27 02:38:35 +08:00
|
|
|
}
|
|
|
|
|
2008-06-29 08:43:07 +08:00
|
|
|
static void HandlePackedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
2008-06-27 02:38:35 +08:00
|
|
|
// check the attribute arguments.
|
2008-06-29 07:36:30 +08:00
|
|
|
if (Attr.getNumArgs() > 0) {
|
2008-11-19 16:23:25 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-06-27 02:38:35 +08:00
|
|
|
if (TagDecl *TD = dyn_cast<TagDecl>(d))
|
2009-08-09 02:23:56 +08:00
|
|
|
TD->addAttr(::new (S.Context) PackedAttr);
|
2008-06-27 02:38:35 +08:00
|
|
|
else if (FieldDecl *FD = dyn_cast<FieldDecl>(d)) {
|
|
|
|
// If the alignment is less than or equal to 8 bits, the packed attribute
|
|
|
|
// has no effect.
|
|
|
|
if (!FD->getType()->isIncompleteType() &&
|
2008-06-29 08:43:07 +08:00
|
|
|
S.Context.getTypeAlign(FD->getType()) <= 8)
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored_for_field_of_type)
|
2008-11-24 05:45:46 +08:00
|
|
|
<< Attr.getName() << FD->getType();
|
2008-06-27 02:38:35 +08:00
|
|
|
else
|
2009-08-09 02:23:56 +08:00
|
|
|
FD->addAttr(::new (S.Context) PackedAttr);
|
2008-06-27 02:38:35 +08:00
|
|
|
} else
|
2008-11-19 16:23:25 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
|
2008-06-27 02:38:35 +08:00
|
|
|
}
|
|
|
|
|
2008-07-16 06:26:48 +08:00
|
|
|
static void HandleIBOutletAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
|
|
|
// check the attribute arguments.
|
|
|
|
if (Attr.getNumArgs() > 0) {
|
2008-11-19 16:23:25 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
|
2008-07-16 06:26:48 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-07-16 06:26:48 +08:00
|
|
|
// The IBOutlet attribute only applies to instance variables of Objective-C
|
|
|
|
// classes.
|
2009-02-18 06:20:20 +08:00
|
|
|
if (isa<ObjCIvarDecl>(d) || isa<ObjCPropertyDecl>(d))
|
2009-06-30 10:34:44 +08:00
|
|
|
d->addAttr(::new (S.Context) IBOutletAttr());
|
2008-07-16 06:26:48 +08:00
|
|
|
else
|
2009-02-18 06:20:20 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_iboutlet);
|
2008-07-16 06:26:48 +08:00
|
|
|
}
|
|
|
|
|
2008-07-22 05:53:04 +08:00
|
|
|
static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
2009-07-25 03:02:52 +08:00
|
|
|
// GCC ignores the nonnull attribute on K&R style function prototypes, so we
|
|
|
|
// ignore it as well
|
2008-10-19 10:04:16 +08:00
|
|
|
if (!isFunctionOrMethod(d) || !hasFunctionProto(d)) {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
2009-05-14 05:07:32 +08:00
|
|
|
<< Attr.getName() << 0 /*function*/;
|
2008-07-22 05:53:04 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-10-19 10:04:16 +08:00
|
|
|
unsigned NumArgs = getFunctionOrMethodNumArgs(d);
|
2008-07-22 05:53:04 +08:00
|
|
|
|
|
|
|
// The nonnull attribute only applies to pointers.
|
|
|
|
llvm::SmallVector<unsigned, 10> NonNullArgs;
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-07-22 05:53:04 +08:00
|
|
|
for (AttributeList::arg_iterator I=Attr.arg_begin(),
|
|
|
|
E=Attr.arg_end(); I!=E; ++I) {
|
2009-07-25 03:02:52 +08:00
|
|
|
|
|
|
|
|
2008-07-22 05:53:04 +08:00
|
|
|
// The argument must be an integer constant expression.
|
2008-12-05 03:38:33 +08:00
|
|
|
Expr *Ex = static_cast<Expr *>(*I);
|
2008-07-22 05:53:04 +08:00
|
|
|
llvm::APSInt ArgNum(32);
|
|
|
|
if (!Ex->isIntegerConstantExpr(ArgNum, S.Context)) {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
|
|
|
|
<< "nonnull" << Ex->getSourceRange();
|
2008-07-22 05:53:04 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-07-22 05:53:04 +08:00
|
|
|
unsigned x = (unsigned) ArgNum.getZExtValue();
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-07-22 05:53:04 +08:00
|
|
|
if (x < 1 || x > NumArgs) {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
|
2008-11-19 15:22:31 +08:00
|
|
|
<< "nonnull" << I.getArgNum() << Ex->getSourceRange();
|
2008-07-22 05:53:04 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-07-22 06:09:15 +08:00
|
|
|
--x;
|
2008-07-22 05:53:04 +08:00
|
|
|
|
|
|
|
// Is the function argument a pointer type?
|
2009-07-25 03:02:52 +08:00
|
|
|
QualType T = getFunctionOrMethodArgType(d, x);
|
2009-07-16 07:23:54 +08:00
|
|
|
if (!T->isAnyPointerType() && !T->isBlockPointerType()) {
|
2008-07-22 05:53:04 +08:00
|
|
|
// FIXME: Should also highlight argument in decl.
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_nonnull_pointers_only)
|
|
|
|
<< "nonnull" << Ex->getSourceRange();
|
2008-09-02 03:57:52 +08:00
|
|
|
continue;
|
2008-07-22 05:53:04 +08:00
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-07-22 05:53:04 +08:00
|
|
|
NonNullArgs.push_back(x);
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
|
|
|
// If no arguments were specified to __attribute__((nonnull)) then all pointer
|
|
|
|
// arguments have a nonnull attribute.
|
2008-09-02 03:57:52 +08:00
|
|
|
if (NonNullArgs.empty()) {
|
2008-11-18 14:52:58 +08:00
|
|
|
for (unsigned I = 0, E = getFunctionOrMethodNumArgs(d); I != E; ++I) {
|
|
|
|
QualType T = getFunctionOrMethodArgType(d, I);
|
2009-07-16 07:23:54 +08:00
|
|
|
if (T->isAnyPointerType() || T->isBlockPointerType())
|
2008-10-19 10:04:16 +08:00
|
|
|
NonNullArgs.push_back(I);
|
2008-11-18 14:52:58 +08:00
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-09-02 03:57:52 +08:00
|
|
|
if (NonNullArgs.empty()) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_nonnull_no_pointers);
|
|
|
|
return;
|
|
|
|
}
|
2008-07-22 05:53:04 +08:00
|
|
|
}
|
2008-09-02 03:57:52 +08:00
|
|
|
|
|
|
|
unsigned* start = &NonNullArgs[0];
|
|
|
|
unsigned size = NonNullArgs.size();
|
|
|
|
std::sort(start, start + size);
|
2009-06-30 10:34:44 +08:00
|
|
|
d->addAttr(::new (S.Context) NonNullAttr(start, size));
|
2008-07-22 05:53:04 +08:00
|
|
|
}
|
|
|
|
|
2008-06-29 08:43:07 +08:00
|
|
|
static void HandleAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
2008-06-27 02:38:35 +08:00
|
|
|
// check the attribute arguments.
|
2008-06-29 07:36:30 +08:00
|
|
|
if (Attr.getNumArgs() != 1) {
|
2008-11-19 16:23:25 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-06-29 07:36:30 +08:00
|
|
|
Expr *Arg = static_cast<Expr*>(Attr.getArg(0));
|
2008-06-27 02:38:35 +08:00
|
|
|
Arg = Arg->IgnoreParenCasts();
|
|
|
|
StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-06-27 02:38:35 +08:00
|
|
|
if (Str == 0 || Str->isWide()) {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
|
2008-11-19 16:23:25 +08:00
|
|
|
<< "alias" << 1;
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-06-27 02:38:35 +08:00
|
|
|
const char *Alias = Str->getStrData();
|
|
|
|
unsigned AliasLen = Str->getByteLength();
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-06-27 02:38:35 +08:00
|
|
|
// FIXME: check if target symbol exists in current file
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
d->addAttr(::new (S.Context) AliasAttr(std::string(Alias, AliasLen)));
|
2008-06-27 02:38:35 +08:00
|
|
|
}
|
|
|
|
|
2009-07-25 03:02:52 +08:00
|
|
|
static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr,
|
2008-10-28 08:17:57 +08:00
|
|
|
Sema &S) {
|
|
|
|
// check the attribute arguments.
|
|
|
|
if (Attr.getNumArgs() != 0) {
|
2008-11-19 16:23:25 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
|
2008-10-28 08:17:57 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-02-20 03:16:48 +08:00
|
|
|
|
2009-04-15 01:02:11 +08:00
|
|
|
if (!isa<FunctionDecl>(d)) {
|
2009-02-20 03:16:48 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
2009-05-14 05:07:32 +08:00
|
|
|
<< Attr.getName() << 0 /*function*/;
|
2009-02-20 03:16:48 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
d->addAttr(::new (S.Context) AlwaysInlineAttr());
|
2008-10-28 08:17:57 +08:00
|
|
|
}
|
|
|
|
|
2009-08-10 04:07:29 +08:00
|
|
|
static void HandleMallocAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
|
|
|
// check the attribute arguments.
|
|
|
|
if (Attr.getNumArgs() != 0) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
|
|
|
|
return;
|
|
|
|
}
|
2009-08-15 06:03:27 +08:00
|
|
|
|
2009-08-15 08:51:46 +08:00
|
|
|
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(d)) {
|
|
|
|
QualType RetTy = FD->getResultType();
|
|
|
|
if (RetTy->isAnyPointerType() || RetTy->isBlockPointerType()) {
|
|
|
|
d->addAttr(::new (S.Context) MallocAttr());
|
|
|
|
return;
|
|
|
|
}
|
2009-08-10 06:36:29 +08:00
|
|
|
}
|
|
|
|
|
2009-08-15 08:51:46 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_malloc_pointer_only);
|
2009-08-10 04:07:29 +08:00
|
|
|
}
|
|
|
|
|
2009-04-10 08:01:14 +08:00
|
|
|
static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr,
|
2009-05-14 05:07:32 +08:00
|
|
|
Sema &S) {
|
2008-06-27 02:38:35 +08:00
|
|
|
// check the attribute arguments.
|
2008-06-29 07:36:30 +08:00
|
|
|
if (Attr.getNumArgs() != 0) {
|
2008-11-19 16:23:25 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
|
2009-04-10 08:01:14 +08:00
|
|
|
return false;
|
2008-06-27 02:38:35 +08:00
|
|
|
}
|
2008-10-19 10:04:16 +08:00
|
|
|
|
2009-04-30 03:03:13 +08:00
|
|
|
if (!isFunctionOrMethod(d) && !isa<BlockDecl>(d)) {
|
|
|
|
ValueDecl *VD = dyn_cast<ValueDecl>(d);
|
|
|
|
if (VD == 0 || !VD->getType()->isBlockPointerType()) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
2009-05-14 05:07:32 +08:00
|
|
|
<< Attr.getName() << 0 /*function*/;
|
2009-04-30 03:03:13 +08:00
|
|
|
return false;
|
|
|
|
}
|
2008-06-27 02:38:35 +08:00
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-04-10 08:01:14 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void HandleNoReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
2009-07-25 03:02:52 +08:00
|
|
|
if (HandleCommonNoReturnAttr(d, Attr, S))
|
2009-06-30 10:34:44 +08:00
|
|
|
d->addAttr(::new (S.Context) NoReturnAttr());
|
2009-04-10 08:01:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr,
|
|
|
|
Sema &S) {
|
2009-07-25 03:02:52 +08:00
|
|
|
if (HandleCommonNoReturnAttr(d, Attr, S))
|
2009-06-30 10:34:44 +08:00
|
|
|
d->addAttr(::new (S.Context) AnalyzerNoReturnAttr());
|
2008-06-27 02:38:35 +08:00
|
|
|
}
|
|
|
|
|
2008-07-25 12:39:19 +08:00
|
|
|
static void HandleUnusedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
|
|
|
// check the attribute arguments.
|
|
|
|
if (Attr.getNumArgs() != 0) {
|
2008-11-19 16:23:25 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
|
2008-07-25 12:39:19 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-10-19 10:04:16 +08:00
|
|
|
if (!isa<VarDecl>(d) && !isFunctionOrMethod(d)) {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
2009-05-14 05:07:32 +08:00
|
|
|
<< Attr.getName() << 2 /*variable and function*/;
|
2008-07-25 12:39:19 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
d->addAttr(::new (S.Context) UnusedAttr());
|
2008-07-25 12:39:19 +08:00
|
|
|
}
|
|
|
|
|
2009-02-14 03:23:53 +08:00
|
|
|
static void HandleUsedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
|
|
|
// check the attribute arguments.
|
|
|
|
if (Attr.getNumArgs() != 0) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
|
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-02-14 03:23:53 +08:00
|
|
|
if (const VarDecl *VD = dyn_cast<VarDecl>(d)) {
|
2009-02-14 06:48:56 +08:00
|
|
|
if (VD->hasLocalStorage() || VD->hasExternalStorage()) {
|
2009-02-14 03:23:53 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "used";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else if (!isFunctionOrMethod(d)) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
2009-05-14 05:07:32 +08:00
|
|
|
<< Attr.getName() << 2 /*variable and function*/;
|
2009-02-14 03:23:53 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
d->addAttr(::new (S.Context) UsedAttr());
|
2009-02-14 03:23:53 +08:00
|
|
|
}
|
|
|
|
|
2008-08-01 06:40:48 +08:00
|
|
|
static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
|
|
|
// check the attribute arguments.
|
|
|
|
if (Attr.getNumArgs() != 0 && Attr.getNumArgs() != 1) {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
|
|
|
|
<< "0 or 1";
|
2008-08-01 06:40:48 +08:00
|
|
|
return;
|
2009-07-25 03:02:52 +08:00
|
|
|
}
|
2008-08-01 06:40:48 +08:00
|
|
|
|
|
|
|
int priority = 65535; // FIXME: Do not hardcode such constants.
|
|
|
|
if (Attr.getNumArgs() > 0) {
|
|
|
|
Expr *E = static_cast<Expr *>(Attr.getArg(0));
|
|
|
|
llvm::APSInt Idx(32);
|
|
|
|
if (!E->isIntegerConstantExpr(Idx, S.Context)) {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
|
2008-11-19 16:23:25 +08:00
|
|
|
<< "constructor" << 1 << E->getSourceRange();
|
2008-08-01 06:40:48 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
priority = Idx.getZExtValue();
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-04-15 01:02:11 +08:00
|
|
|
if (!isa<FunctionDecl>(d)) {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
2009-05-14 05:07:32 +08:00
|
|
|
<< Attr.getName() << 0 /*function*/;
|
2008-08-01 06:40:48 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
d->addAttr(::new (S.Context) ConstructorAttr(priority));
|
2008-08-01 06:40:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
|
|
|
// check the attribute arguments.
|
|
|
|
if (Attr.getNumArgs() != 0 && Attr.getNumArgs() != 1) {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
|
|
|
|
<< "0 or 1";
|
2008-08-01 06:40:48 +08:00
|
|
|
return;
|
2009-07-25 03:02:52 +08:00
|
|
|
}
|
2008-08-01 06:40:48 +08:00
|
|
|
|
|
|
|
int priority = 65535; // FIXME: Do not hardcode such constants.
|
|
|
|
if (Attr.getNumArgs() > 0) {
|
|
|
|
Expr *E = static_cast<Expr *>(Attr.getArg(0));
|
|
|
|
llvm::APSInt Idx(32);
|
|
|
|
if (!E->isIntegerConstantExpr(Idx, S.Context)) {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
|
2008-11-19 16:23:25 +08:00
|
|
|
<< "destructor" << 1 << E->getSourceRange();
|
2008-08-01 06:40:48 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
priority = Idx.getZExtValue();
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-08-23 06:10:48 +08:00
|
|
|
if (!isa<FunctionDecl>(d)) {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
2009-05-14 05:07:32 +08:00
|
|
|
<< Attr.getName() << 0 /*function*/;
|
2008-08-01 06:40:48 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
d->addAttr(::new (S.Context) DestructorAttr(priority));
|
2008-08-01 06:40:48 +08:00
|
|
|
}
|
|
|
|
|
2008-06-29 08:43:07 +08:00
|
|
|
static void HandleDeprecatedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
2008-06-27 02:38:35 +08:00
|
|
|
// check the attribute arguments.
|
2008-06-29 07:36:30 +08:00
|
|
|
if (Attr.getNumArgs() != 0) {
|
2008-11-19 16:23:25 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
d->addAttr(::new (S.Context) DeprecatedAttr());
|
2008-06-27 02:38:35 +08:00
|
|
|
}
|
|
|
|
|
2008-12-17 09:07:27 +08:00
|
|
|
static void HandleUnavailableAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
|
|
|
// check the attribute arguments.
|
|
|
|
if (Attr.getNumArgs() != 0) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
|
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
d->addAttr(::new (S.Context) UnavailableAttr());
|
2008-12-17 09:07:27 +08:00
|
|
|
}
|
|
|
|
|
2008-06-29 08:43:07 +08:00
|
|
|
static void HandleVisibilityAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
2008-06-27 02:38:35 +08:00
|
|
|
// check the attribute arguments.
|
2008-06-29 07:36:30 +08:00
|
|
|
if (Attr.getNumArgs() != 1) {
|
2008-11-19 16:23:25 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-06-29 07:36:30 +08:00
|
|
|
Expr *Arg = static_cast<Expr*>(Attr.getArg(0));
|
2008-06-27 02:38:35 +08:00
|
|
|
Arg = Arg->IgnoreParenCasts();
|
|
|
|
StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-06-27 02:38:35 +08:00
|
|
|
if (Str == 0 || Str->isWide()) {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
|
2008-11-19 16:23:25 +08:00
|
|
|
<< "visibility" << 1;
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-06-27 02:38:35 +08:00
|
|
|
const char *TypeStr = Str->getStrData();
|
|
|
|
unsigned TypeLen = Str->getByteLength();
|
|
|
|
VisibilityAttr::VisibilityTypes type;
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-06-27 02:38:35 +08:00
|
|
|
if (TypeLen == 7 && !memcmp(TypeStr, "default", 7))
|
|
|
|
type = VisibilityAttr::DefaultVisibility;
|
|
|
|
else if (TypeLen == 6 && !memcmp(TypeStr, "hidden", 6))
|
|
|
|
type = VisibilityAttr::HiddenVisibility;
|
|
|
|
else if (TypeLen == 8 && !memcmp(TypeStr, "internal", 8))
|
|
|
|
type = VisibilityAttr::HiddenVisibility; // FIXME
|
|
|
|
else if (TypeLen == 9 && !memcmp(TypeStr, "protected", 9))
|
|
|
|
type = VisibilityAttr::ProtectedVisibility;
|
|
|
|
else {
|
2008-11-24 05:45:46 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_unknown_visibility) << TypeStr;
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
d->addAttr(::new (S.Context) VisibilityAttr(type));
|
2008-06-27 02:38:35 +08:00
|
|
|
}
|
|
|
|
|
2009-02-14 16:09:34 +08:00
|
|
|
static void HandleObjCExceptionAttr(Decl *D, const AttributeList &Attr,
|
|
|
|
Sema &S) {
|
|
|
|
if (Attr.getNumArgs() != 0) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
|
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-02-14 16:09:34 +08:00
|
|
|
ObjCInterfaceDecl *OCI = dyn_cast<ObjCInterfaceDecl>(D);
|
|
|
|
if (OCI == 0) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_requires_objc_interface);
|
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
D->addAttr(::new (S.Context) ObjCExceptionAttr());
|
2009-02-14 16:09:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void HandleObjCNSObject(Decl *D, const AttributeList &Attr, Sema &S) {
|
2009-01-14 07:34:40 +08:00
|
|
|
if (Attr.getNumArgs() != 0) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
|
|
|
|
return;
|
|
|
|
}
|
2009-02-14 16:09:34 +08:00
|
|
|
if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
|
2009-01-14 07:34:40 +08:00
|
|
|
QualType T = TD->getUnderlyingType();
|
|
|
|
if (!T->isPointerType() ||
|
2009-07-30 05:53:49 +08:00
|
|
|
!T->getAs<PointerType>()->getPointeeType()->isRecordType()) {
|
2009-01-14 07:34:40 +08:00
|
|
|
S.Diag(TD->getLocation(), diag::err_nsobject_attribute);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2009-06-30 10:34:44 +08:00
|
|
|
D->addAttr(::new (S.Context) ObjCNSObjectAttr());
|
2009-01-14 07:34:40 +08:00
|
|
|
}
|
|
|
|
|
2009-07-25 03:02:52 +08:00
|
|
|
static void
|
Initial implementation of function overloading in C.
This commit adds a new attribute, "overloadable", that enables C++
function overloading in C. The attribute can only be added to function
declarations, e.g.,
int *f(int) __attribute__((overloadable));
If the "overloadable" attribute exists on a function with a given
name, *all* functions with that name (and in that scope) must have the
"overloadable" attribute. Sets of overloaded functions with the
"overloadable" attribute then follow the normal C++ rules for
overloaded functions, e.g., overloads must have different
parameter-type-lists from each other.
When calling an overloaded function in C, we follow the same
overloading rules as C++, with three extensions to the set of standard
conversions:
- A value of a given struct or union type T can be converted to the
type T. This is just the identity conversion. (In C++, this would
go through a copy constructor).
- A value of pointer type T* can be converted to a value of type U*
if T and U are compatible types. This conversion has Conversion
rank (it's considered a pointer conversion in C).
- A value of type T can be converted to a value of type U if T and U
are compatible (and are not both pointer types). This conversion
has Conversion rank (it's considered to be a new kind of
conversion unique to C, a "compatible" conversion).
Known defects (and, therefore, next steps):
1) The standard-conversion handling does not understand conversions
involving _Complex or vector extensions, so it is likely to get
these wrong. We need to add these conversions.
2) All overloadable functions with the same name will have the same
linkage name, which means we'll get a collision in the linker (if
not sooner). We'll need to mangle the names of these functions.
llvm-svn: 64336
2009-02-12 07:02:49 +08:00
|
|
|
HandleOverloadableAttr(Decl *D, const AttributeList &Attr, Sema &S) {
|
|
|
|
if (Attr.getNumArgs() != 0) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isa<FunctionDecl>(D)) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_overloadable_not_function);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
D->addAttr(::new (S.Context) OverloadableAttr());
|
Initial implementation of function overloading in C.
This commit adds a new attribute, "overloadable", that enables C++
function overloading in C. The attribute can only be added to function
declarations, e.g.,
int *f(int) __attribute__((overloadable));
If the "overloadable" attribute exists on a function with a given
name, *all* functions with that name (and in that scope) must have the
"overloadable" attribute. Sets of overloaded functions with the
"overloadable" attribute then follow the normal C++ rules for
overloaded functions, e.g., overloads must have different
parameter-type-lists from each other.
When calling an overloaded function in C, we follow the same
overloading rules as C++, with three extensions to the set of standard
conversions:
- A value of a given struct or union type T can be converted to the
type T. This is just the identity conversion. (In C++, this would
go through a copy constructor).
- A value of pointer type T* can be converted to a value of type U*
if T and U are compatible types. This conversion has Conversion
rank (it's considered a pointer conversion in C).
- A value of type T can be converted to a value of type U if T and U
are compatible (and are not both pointer types). This conversion
has Conversion rank (it's considered to be a new kind of
conversion unique to C, a "compatible" conversion).
Known defects (and, therefore, next steps):
1) The standard-conversion handling does not understand conversions
involving _Complex or vector extensions, so it is likely to get
these wrong. We need to add these conversions.
2) All overloadable functions with the same name will have the same
linkage name, which means we'll get a collision in the linker (if
not sooner). We'll need to mangle the names of these functions.
llvm-svn: 64336
2009-02-12 07:02:49 +08:00
|
|
|
}
|
|
|
|
|
2008-09-19 00:44:58 +08:00
|
|
|
static void HandleBlocksAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
2009-07-25 03:02:52 +08:00
|
|
|
if (!Attr.getParameterName()) {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
|
2008-11-19 16:23:25 +08:00
|
|
|
<< "blocks" << 1;
|
2008-09-19 00:44:58 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-09-19 00:44:58 +08:00
|
|
|
if (Attr.getNumArgs() != 0) {
|
2008-11-19 16:23:25 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
|
2008-09-19 00:44:58 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-09-19 00:44:58 +08:00
|
|
|
BlocksAttr::BlocksAttrTypes type;
|
2008-11-20 12:42:34 +08:00
|
|
|
if (Attr.getParameterName()->isStr("byref"))
|
2008-09-19 00:44:58 +08:00
|
|
|
type = BlocksAttr::ByRef;
|
|
|
|
else {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported)
|
2008-11-19 16:23:25 +08:00
|
|
|
<< "blocks" << Attr.getParameterName();
|
2008-09-19 00:44:58 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
d->addAttr(::new (S.Context) BlocksAttr(type));
|
2008-09-19 00:44:58 +08:00
|
|
|
}
|
|
|
|
|
2008-10-06 02:05:59 +08:00
|
|
|
static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
|
|
|
// check the attribute arguments.
|
|
|
|
if (Attr.getNumArgs() > 2) {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
|
|
|
|
<< "0, 1 or 2";
|
2008-10-06 02:05:59 +08:00
|
|
|
return;
|
2009-07-25 03:02:52 +08:00
|
|
|
}
|
|
|
|
|
2008-10-06 02:05:59 +08:00
|
|
|
int sentinel = 0;
|
|
|
|
if (Attr.getNumArgs() > 0) {
|
|
|
|
Expr *E = static_cast<Expr *>(Attr.getArg(0));
|
|
|
|
llvm::APSInt Idx(32);
|
|
|
|
if (!E->isIntegerConstantExpr(Idx, S.Context)) {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
|
2008-11-19 16:23:25 +08:00
|
|
|
<< "sentinel" << 1 << E->getSourceRange();
|
2008-10-06 02:05:59 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
sentinel = Idx.getZExtValue();
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-10-06 02:05:59 +08:00
|
|
|
if (sentinel < 0) {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_sentinel_less_than_zero)
|
|
|
|
<< E->getSourceRange();
|
2008-10-06 02:05:59 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int nullPos = 0;
|
|
|
|
if (Attr.getNumArgs() > 1) {
|
|
|
|
Expr *E = static_cast<Expr *>(Attr.getArg(1));
|
|
|
|
llvm::APSInt Idx(32);
|
|
|
|
if (!E->isIntegerConstantExpr(Idx, S.Context)) {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
|
2008-11-19 16:23:25 +08:00
|
|
|
<< "sentinel" << 2 << E->getSourceRange();
|
2008-10-06 02:05:59 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
nullPos = Idx.getZExtValue();
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-10-06 02:05:59 +08:00
|
|
|
if (nullPos > 1 || nullPos < 0) {
|
|
|
|
// FIXME: This error message could be improved, it would be nice
|
|
|
|
// to say what the bounds actually are.
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_sentinel_not_zero_or_one)
|
|
|
|
<< E->getSourceRange();
|
2008-10-06 02:05:59 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(d)) {
|
2009-03-18 07:03:47 +08:00
|
|
|
const FunctionType *FT = FD->getType()->getAsFunctionType();
|
|
|
|
assert(FT && "FunctionDecl has non-function type?");
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-03-18 07:03:47 +08:00
|
|
|
if (isa<FunctionNoProtoType>(FT)) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_named_arguments);
|
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-03-18 07:03:47 +08:00
|
|
|
if (!cast<FunctionProtoType>(FT)->isVariadic()) {
|
2009-05-16 05:18:04 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0;
|
2008-10-06 02:05:59 +08:00
|
|
|
return;
|
2009-07-25 03:02:52 +08:00
|
|
|
}
|
2008-10-06 02:05:59 +08:00
|
|
|
} else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(d)) {
|
|
|
|
if (!MD->isVariadic()) {
|
2009-05-16 05:18:04 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0;
|
2008-10-06 02:05:59 +08:00
|
|
|
return;
|
2009-05-15 04:53:39 +08:00
|
|
|
}
|
|
|
|
} else if (isa<BlockDecl>(d)) {
|
2009-07-25 03:02:52 +08:00
|
|
|
// Note! BlockDecl is typeless. Variadic diagnostics will be issued by the
|
|
|
|
// caller.
|
2009-05-15 04:53:39 +08:00
|
|
|
;
|
|
|
|
} else if (const VarDecl *V = dyn_cast<VarDecl>(d)) {
|
|
|
|
QualType Ty = V->getType();
|
2009-05-16 04:33:25 +08:00
|
|
|
if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) {
|
2009-07-25 03:02:52 +08:00
|
|
|
const FunctionType *FT = Ty->isFunctionPointerType() ? getFunctionType(d)
|
2009-07-30 05:53:49 +08:00
|
|
|
: Ty->getAs<BlockPointerType>()->getPointeeType()->getAsFunctionType();
|
2009-05-15 04:53:39 +08:00
|
|
|
if (!cast<FunctionProtoType>(FT)->isVariadic()) {
|
2009-05-16 05:18:04 +08:00
|
|
|
int m = Ty->isFunctionPointerType() ? 0 : 1;
|
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << m;
|
2009-05-15 04:53:39 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-08-05 05:02:39 +08:00
|
|
|
} else {
|
2009-05-15 04:53:39 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
2009-05-15 04:57:28 +08:00
|
|
|
<< Attr.getName() << 6 /*function, method or block */;
|
2009-05-15 04:53:39 +08:00
|
|
|
return;
|
|
|
|
}
|
2008-10-06 02:05:59 +08:00
|
|
|
} else {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
2009-05-15 04:57:28 +08:00
|
|
|
<< Attr.getName() << 6 /*function, method or block */;
|
2008-10-06 02:05:59 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-06-30 10:34:44 +08:00
|
|
|
d->addAttr(::new (S.Context) SentinelAttr(sentinel, nullPos));
|
2008-10-06 02:05:59 +08:00
|
|
|
}
|
|
|
|
|
2009-02-14 15:37:35 +08:00
|
|
|
static void HandleWarnUnusedResult(Decl *D, const AttributeList &Attr, Sema &S) {
|
|
|
|
// check the attribute arguments.
|
|
|
|
if (Attr.getNumArgs() != 0) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: could also be applied to methods?
|
|
|
|
FunctionDecl *Fn = dyn_cast<FunctionDecl>(D);
|
|
|
|
if (!Fn) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
2009-05-14 05:07:32 +08:00
|
|
|
<< Attr.getName() << 0 /*function*/;
|
2009-02-14 15:37:35 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
Fn->addAttr(::new (S.Context) WarnUnusedResultAttr());
|
2009-02-14 15:37:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void HandleWeakAttr(Decl *D, const AttributeList &Attr, Sema &S) {
|
2008-06-27 02:38:35 +08:00
|
|
|
// check the attribute arguments.
|
2008-06-29 07:36:30 +08:00
|
|
|
if (Attr.getNumArgs() != 0) {
|
2008-11-19 16:23:25 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-03-06 14:39:57 +08:00
|
|
|
|
2009-07-16 09:12:24 +08:00
|
|
|
/* weak only applies to non-static declarations */
|
|
|
|
bool isStatic = false;
|
|
|
|
if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
|
|
|
|
isStatic = VD->getStorageClass() == VarDecl::Static;
|
|
|
|
} else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
|
|
|
isStatic = FD->getStorageClass() == FunctionDecl::Static;
|
|
|
|
}
|
|
|
|
if (isStatic) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_weak_static) <<
|
|
|
|
dyn_cast<NamedDecl>(D)->getNameAsString();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-03-06 14:39:57 +08:00
|
|
|
// TODO: could also be applied to methods?
|
|
|
|
if (!isa<FunctionDecl>(D) && !isa<VarDecl>(D)) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
2009-05-14 05:07:32 +08:00
|
|
|
<< Attr.getName() << 2 /*variable and function*/;
|
2009-03-06 14:39:57 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
D->addAttr(::new (S.Context) WeakAttr());
|
2008-06-27 02:38:35 +08:00
|
|
|
}
|
|
|
|
|
2009-03-06 14:39:57 +08:00
|
|
|
static void HandleWeakImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
|
|
|
|
// check the attribute arguments.
|
|
|
|
if (Attr.getNumArgs() != 0) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
|
|
|
|
return;
|
2009-07-25 03:02:52 +08:00
|
|
|
}
|
2009-03-06 14:39:57 +08:00
|
|
|
|
|
|
|
// weak_import only applies to variable & function declarations.
|
|
|
|
bool isDef = false;
|
|
|
|
if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
|
|
|
|
isDef = (!VD->hasExternalStorage() || VD->getInit());
|
|
|
|
} else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
2009-06-30 10:35:26 +08:00
|
|
|
isDef = FD->getBody();
|
2009-05-05 03:35:12 +08:00
|
|
|
} else if (isa<ObjCPropertyDecl>(D) || isa<ObjCMethodDecl>(D)) {
|
|
|
|
// We ignore weak import on properties and methods
|
2009-03-19 01:39:31 +08:00
|
|
|
return;
|
2009-03-06 14:39:57 +08:00
|
|
|
} else {
|
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
2009-05-14 05:07:32 +08:00
|
|
|
<< Attr.getName() << 2 /*variable and function*/;
|
2009-03-06 14:39:57 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Merge should handle any subsequent violations.
|
|
|
|
if (isDef) {
|
2009-07-25 03:02:52 +08:00
|
|
|
S.Diag(Attr.getLoc(),
|
2009-03-06 14:39:57 +08:00
|
|
|
diag::warn_attribute_weak_import_invalid_on_definition)
|
|
|
|
<< "weak_import" << 2 /*variable and function*/;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
D->addAttr(::new (S.Context) WeakImportAttr());
|
2009-03-06 14:39:57 +08:00
|
|
|
}
|
|
|
|
|
2009-02-14 15:37:35 +08:00
|
|
|
static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
|
2008-06-27 02:38:35 +08:00
|
|
|
// check the attribute arguments.
|
2008-06-29 07:36:30 +08:00
|
|
|
if (Attr.getNumArgs() != 0) {
|
2008-11-19 16:23:25 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
2008-12-24 06:24:07 +08:00
|
|
|
|
2008-12-26 08:52:02 +08:00
|
|
|
// Attribute can be applied only to functions or variables.
|
2009-02-14 15:37:35 +08:00
|
|
|
if (isa<VarDecl>(D)) {
|
2009-06-30 10:34:44 +08:00
|
|
|
D->addAttr(::new (S.Context) DLLImportAttr());
|
2008-12-26 08:52:02 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-02-14 15:37:35 +08:00
|
|
|
FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
|
2008-12-26 08:52:02 +08:00
|
|
|
if (!FD) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
2009-05-14 05:07:32 +08:00
|
|
|
<< Attr.getName() << 2 /*variable and function*/;
|
2008-12-26 08:52:02 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Currently, the dllimport attribute is ignored for inlined functions.
|
|
|
|
// Warning is emitted.
|
|
|
|
if (FD->isInline()) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The attribute is also overridden by a subsequent declaration as dllexport.
|
|
|
|
// Warning is emitted.
|
|
|
|
for (AttributeList *nextAttr = Attr.getNext(); nextAttr;
|
|
|
|
nextAttr = nextAttr->getNext()) {
|
|
|
|
if (nextAttr->getKind() == AttributeList::AT_dllexport) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
if (D->getAttr<DLLExportAttr>()) {
|
2008-12-26 08:52:02 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
D->addAttr(::new (S.Context) DLLImportAttr());
|
2008-06-27 02:38:35 +08:00
|
|
|
}
|
|
|
|
|
2009-02-14 15:37:35 +08:00
|
|
|
static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
|
2008-06-27 02:38:35 +08:00
|
|
|
// check the attribute arguments.
|
2008-06-29 07:36:30 +08:00
|
|
|
if (Attr.getNumArgs() != 0) {
|
2008-11-19 16:23:25 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
2008-12-24 06:24:07 +08:00
|
|
|
|
2008-12-26 08:52:02 +08:00
|
|
|
// Attribute can be applied only to functions or variables.
|
2009-02-14 15:37:35 +08:00
|
|
|
if (isa<VarDecl>(D)) {
|
2009-06-30 10:34:44 +08:00
|
|
|
D->addAttr(::new (S.Context) DLLExportAttr());
|
2008-12-26 08:52:02 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-02-14 15:37:35 +08:00
|
|
|
FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
|
2008-12-26 08:52:02 +08:00
|
|
|
if (!FD) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
2009-05-14 05:07:32 +08:00
|
|
|
<< Attr.getName() << 2 /*variable and function*/;
|
2008-12-26 08:52:02 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-07-25 03:02:52 +08:00
|
|
|
// Currently, the dllexport attribute is ignored for inlined functions, unless
|
|
|
|
// the -fkeep-inline-functions flag has been used. Warning is emitted;
|
2008-12-26 08:52:02 +08:00
|
|
|
if (FD->isInline()) {
|
|
|
|
// FIXME: ... unless the -fkeep-inline-functions flag has been used.
|
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllexport";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
D->addAttr(::new (S.Context) DLLExportAttr());
|
2008-06-27 02:38:35 +08:00
|
|
|
}
|
|
|
|
|
2009-06-26 14:32:41 +08:00
|
|
|
static void HandleReqdWorkGroupSize(Decl *D, const AttributeList &Attr,
|
|
|
|
Sema &S) {
|
|
|
|
// Attribute has 3 arguments.
|
|
|
|
if (Attr.getNumArgs() != 3) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned WGSize[3];
|
|
|
|
for (unsigned i = 0; i < 3; ++i) {
|
|
|
|
Expr *E = static_cast<Expr *>(Attr.getArg(i));
|
|
|
|
llvm::APSInt ArgNum(32);
|
|
|
|
if (!E->isIntegerConstantExpr(ArgNum, S.Context)) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
|
|
|
|
<< "reqd_work_group_size" << E->getSourceRange();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
WGSize[i] = (unsigned) ArgNum.getZExtValue();
|
|
|
|
}
|
2009-06-30 10:34:44 +08:00
|
|
|
D->addAttr(::new (S.Context) ReqdWorkGroupSizeAttr(WGSize[0], WGSize[1],
|
2009-06-26 14:32:41 +08:00
|
|
|
WGSize[2]));
|
|
|
|
}
|
|
|
|
|
2009-02-14 15:37:35 +08:00
|
|
|
static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) {
|
2009-02-13 01:28:23 +08:00
|
|
|
// Attribute has no arguments.
|
|
|
|
if (Attr.getNumArgs() != 1) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure that there is a string literal as the sections's single
|
|
|
|
// argument.
|
2009-08-11 03:03:04 +08:00
|
|
|
Expr *ArgExpr = static_cast<Expr *>(Attr.getArg(0));
|
|
|
|
StringLiteral *SE = dyn_cast<StringLiteral>(ArgExpr);
|
2009-02-13 01:28:23 +08:00
|
|
|
if (!SE) {
|
2009-08-11 03:03:04 +08:00
|
|
|
S.Diag(ArgExpr->getLocStart(), diag::err_attribute_not_string) << "section";
|
2009-02-13 01:28:23 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-08-11 03:03:04 +08:00
|
|
|
|
|
|
|
std::string SectionStr(SE->getStrData(), SE->getByteLength());
|
|
|
|
|
|
|
|
// If the target wants to validate the section specifier, make it happen.
|
|
|
|
std::string Error = S.Context.Target.isValidSectionSpecifier(SectionStr);
|
|
|
|
if (Error.empty()) {
|
|
|
|
D->addAttr(::new (S.Context) SectionAttr(SectionStr));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
S.Diag(SE->getLocStart(), diag::err_attribute_section_invalid_for_target)
|
|
|
|
<< Error;
|
|
|
|
|
2009-02-13 01:28:23 +08:00
|
|
|
}
|
|
|
|
|
2008-06-29 08:43:07 +08:00
|
|
|
static void HandleStdCallAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
2008-12-24 06:24:07 +08:00
|
|
|
// Attribute has no arguments.
|
2008-06-29 07:36:30 +08:00
|
|
|
if (Attr.getNumArgs() != 0) {
|
2008-11-19 16:23:25 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
2008-12-24 06:24:07 +08:00
|
|
|
|
|
|
|
// Attribute can be applied only to functions.
|
|
|
|
if (!isa<FunctionDecl>(d)) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
2009-05-14 05:07:32 +08:00
|
|
|
<< Attr.getName() << 0 /*function*/;
|
2008-12-24 06:24:07 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// stdcall and fastcall attributes are mutually incompatible.
|
2009-06-30 10:34:44 +08:00
|
|
|
if (d->getAttr<FastCallAttr>()) {
|
2008-12-24 06:24:07 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
|
|
|
|
<< "stdcall" << "fastcall";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
d->addAttr(::new (S.Context) StdCallAttr());
|
2008-06-27 02:38:35 +08:00
|
|
|
}
|
|
|
|
|
2008-06-29 08:43:07 +08:00
|
|
|
static void HandleFastCallAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
2008-12-24 06:24:07 +08:00
|
|
|
// Attribute has no arguments.
|
2008-06-29 07:36:30 +08:00
|
|
|
if (Attr.getNumArgs() != 0) {
|
2008-11-19 16:23:25 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
2008-12-24 06:24:07 +08:00
|
|
|
|
|
|
|
if (!isa<FunctionDecl>(d)) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
2009-05-14 05:07:32 +08:00
|
|
|
<< Attr.getName() << 0 /*function*/;
|
2008-12-24 06:24:07 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// stdcall and fastcall attributes are mutually incompatible.
|
2009-06-30 10:34:44 +08:00
|
|
|
if (d->getAttr<StdCallAttr>()) {
|
2008-12-24 06:24:07 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
|
|
|
|
<< "fastcall" << "stdcall";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
d->addAttr(::new (S.Context) FastCallAttr());
|
2008-06-27 02:38:35 +08:00
|
|
|
}
|
|
|
|
|
2008-06-29 08:43:07 +08:00
|
|
|
static void HandleNothrowAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
2008-06-27 02:38:35 +08:00
|
|
|
// check the attribute arguments.
|
2008-06-29 07:36:30 +08:00
|
|
|
if (Attr.getNumArgs() != 0) {
|
2008-11-19 16:23:25 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
d->addAttr(::new (S.Context) NoThrowAttr());
|
2008-06-27 02:38:35 +08:00
|
|
|
}
|
|
|
|
|
2008-10-06 07:32:53 +08:00
|
|
|
static void HandleConstAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
|
|
|
// check the attribute arguments.
|
|
|
|
if (Attr.getNumArgs() != 0) {
|
2008-11-19 16:23:25 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
|
2008-10-06 07:32:53 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
d->addAttr(::new (S.Context) ConstAttr());
|
2008-10-06 07:32:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void HandlePureAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
|
|
|
// check the attribute arguments.
|
|
|
|
if (Attr.getNumArgs() != 0) {
|
2008-11-19 16:23:25 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
|
2008-10-06 07:32:53 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
d->addAttr(::new (S.Context) PureAttr());
|
2008-10-06 07:32:53 +08:00
|
|
|
}
|
|
|
|
|
2009-01-31 09:16:18 +08:00
|
|
|
static void HandleCleanupAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
2009-02-08 07:16:50 +08:00
|
|
|
// Match gcc which ignores cleanup attrs when compiling C++.
|
|
|
|
if (S.getLangOptions().CPlusPlus)
|
|
|
|
return;
|
2009-07-25 03:02:52 +08:00
|
|
|
|
|
|
|
if (!Attr.getParameterName()) {
|
2009-01-31 09:16:18 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
|
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-01-31 09:16:18 +08:00
|
|
|
if (Attr.getNumArgs() != 0) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
|
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-01-31 09:16:18 +08:00
|
|
|
VarDecl *VD = dyn_cast<VarDecl>(d);
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-01-31 09:16:18 +08:00
|
|
|
if (!VD || !VD->hasLocalStorage()) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "cleanup";
|
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-01-31 09:16:18 +08:00
|
|
|
// Look up the function
|
2009-02-05 01:27:36 +08:00
|
|
|
NamedDecl *CleanupDecl = S.LookupName(S.TUScope, Attr.getParameterName(),
|
|
|
|
Sema::LookupOrdinaryName);
|
2009-01-31 09:16:18 +08:00
|
|
|
if (!CleanupDecl) {
|
2009-02-08 07:16:50 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_cleanup_arg_not_found) <<
|
2009-01-31 09:16:18 +08:00
|
|
|
Attr.getParameterName();
|
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-01-31 09:16:18 +08:00
|
|
|
FunctionDecl *FD = dyn_cast<FunctionDecl>(CleanupDecl);
|
|
|
|
if (!FD) {
|
2009-02-08 07:16:50 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_cleanup_arg_not_function) <<
|
2009-01-31 09:16:18 +08:00
|
|
|
Attr.getParameterName();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FD->getNumParams() != 1) {
|
2009-02-08 07:16:50 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_cleanup_func_must_take_one_arg) <<
|
2009-01-31 09:16:18 +08:00
|
|
|
Attr.getParameterName();
|
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-02-08 07:16:50 +08:00
|
|
|
// We're currently more strict than GCC about what function types we accept.
|
|
|
|
// If this ever proves to be a problem it should be easy to fix.
|
|
|
|
QualType Ty = S.Context.getPointerType(VD->getType());
|
|
|
|
QualType ParamTy = FD->getParamDecl(0)->getType();
|
2009-04-26 09:30:08 +08:00
|
|
|
if (S.CheckAssignmentConstraints(ParamTy, Ty) != Sema::Compatible) {
|
2009-07-25 03:02:52 +08:00
|
|
|
S.Diag(Attr.getLoc(),
|
2009-02-08 07:16:50 +08:00
|
|
|
diag::err_attribute_cleanup_func_arg_incompatible_type) <<
|
|
|
|
Attr.getParameterName() << ParamTy << Ty;
|
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
d->addAttr(::new (S.Context) CleanupAttr(FD));
|
2009-01-31 09:16:18 +08:00
|
|
|
}
|
|
|
|
|
2009-07-25 03:02:52 +08:00
|
|
|
/// Handle __attribute__((format_arg((idx)))) attribute based on
|
|
|
|
/// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
|
|
|
|
static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
2009-05-21 01:41:43 +08:00
|
|
|
if (Attr.getNumArgs() != 1) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!isFunctionOrMethod(d) || !hasFunctionProto(d)) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
|
|
|
<< Attr.getName() << 0 /*function*/;
|
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
// FIXME: in C++ the implicit 'this' function parameter also counts. this is
|
|
|
|
// needed in order to be compatible with GCC the index must start with 1.
|
2009-05-21 01:41:43 +08:00
|
|
|
unsigned NumArgs = getFunctionOrMethodNumArgs(d);
|
|
|
|
unsigned FirstIdx = 1;
|
|
|
|
// checks for the 2nd argument
|
|
|
|
Expr *IdxExpr = static_cast<Expr *>(Attr.getArg(0));
|
|
|
|
llvm::APSInt Idx(32);
|
|
|
|
if (!IdxExpr->isIntegerConstantExpr(Idx, S.Context)) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
|
|
|
|
<< "format" << 2 << IdxExpr->getSourceRange();
|
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-05-21 01:41:43 +08:00
|
|
|
if (Idx.getZExtValue() < FirstIdx || Idx.getZExtValue() > NumArgs) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
|
|
|
|
<< "format" << 2 << IdxExpr->getSourceRange();
|
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-05-21 01:41:43 +08:00
|
|
|
unsigned ArgIdx = Idx.getZExtValue() - 1;
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-05-21 01:41:43 +08:00
|
|
|
// make sure the format string is really a string
|
|
|
|
QualType Ty = getFunctionOrMethodArgType(d, ArgIdx);
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-05-21 01:41:43 +08:00
|
|
|
bool not_nsstring_type = !isNSStringType(Ty, S.Context);
|
|
|
|
if (not_nsstring_type &&
|
|
|
|
!isCFStringType(Ty, S.Context) &&
|
|
|
|
(!Ty->isPointerType() ||
|
2009-07-30 05:53:49 +08:00
|
|
|
!Ty->getAs<PointerType>()->getPointeeType()->isCharType())) {
|
2009-05-21 01:41:43 +08:00
|
|
|
// FIXME: Should highlight the actual expression that has the wrong type.
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_format_attribute_not)
|
2009-07-25 03:02:52 +08:00
|
|
|
<< (not_nsstring_type ? "a string type" : "an NSString")
|
2009-05-21 01:41:43 +08:00
|
|
|
<< IdxExpr->getSourceRange();
|
|
|
|
return;
|
2009-07-25 03:02:52 +08:00
|
|
|
}
|
2009-05-21 01:41:43 +08:00
|
|
|
Ty = getFunctionOrMethodResultType(d);
|
|
|
|
if (!isNSStringType(Ty, S.Context) &&
|
|
|
|
!isCFStringType(Ty, S.Context) &&
|
|
|
|
(!Ty->isPointerType() ||
|
2009-07-30 05:53:49 +08:00
|
|
|
!Ty->getAs<PointerType>()->getPointeeType()->isCharType())) {
|
2009-05-21 01:41:43 +08:00
|
|
|
// FIXME: Should highlight the actual expression that has the wrong type.
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_format_attribute_result_not)
|
2009-07-25 03:02:52 +08:00
|
|
|
<< (not_nsstring_type ? "string type" : "NSString")
|
2009-05-21 01:41:43 +08:00
|
|
|
<< IdxExpr->getSourceRange();
|
|
|
|
return;
|
2009-07-25 03:02:52 +08:00
|
|
|
}
|
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
d->addAttr(::new (S.Context) FormatArgAttr(Idx.getZExtValue()));
|
2009-05-21 01:41:43 +08:00
|
|
|
}
|
|
|
|
|
2009-07-25 03:02:52 +08:00
|
|
|
/// Handle __attribute__((format(type,idx,firstarg))) attributes based on
|
|
|
|
/// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
|
2008-06-29 08:43:07 +08:00
|
|
|
static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
2008-06-27 02:38:35 +08:00
|
|
|
|
2008-06-29 07:36:30 +08:00
|
|
|
if (!Attr.getParameterName()) {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
|
2008-11-19 16:23:25 +08:00
|
|
|
<< "format" << 1;
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-06-29 07:36:30 +08:00
|
|
|
if (Attr.getNumArgs() != 2) {
|
2008-11-19 16:23:25 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 3;
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-05-16 07:15:03 +08:00
|
|
|
if (!isFunctionOrMethodOrBlock(d) || !hasFunctionProto(d)) {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
2009-05-14 05:07:32 +08:00
|
|
|
<< Attr.getName() << 0 /*function*/;
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-07-25 03:02:52 +08:00
|
|
|
// FIXME: in C++ the implicit 'this' function parameter also counts. this is
|
|
|
|
// needed in order to be compatible with GCC the index must start in 1 and the
|
|
|
|
// limit is numargs+1
|
2008-09-26 12:12:28 +08:00
|
|
|
unsigned NumArgs = getFunctionOrMethodNumArgs(d);
|
2008-06-27 02:38:35 +08:00
|
|
|
unsigned FirstIdx = 1;
|
|
|
|
|
2008-06-29 07:36:30 +08:00
|
|
|
const char *Format = Attr.getParameterName()->getName();
|
|
|
|
unsigned FormatLen = Attr.getParameterName()->getLength();
|
2008-06-27 02:38:35 +08:00
|
|
|
|
|
|
|
// Normalize the argument, __foo__ becomes foo.
|
|
|
|
if (FormatLen > 4 && Format[0] == '_' && Format[1] == '_' &&
|
|
|
|
Format[FormatLen - 2] == '_' && Format[FormatLen - 1] == '_') {
|
|
|
|
Format += 2;
|
|
|
|
FormatLen -= 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Supported = false;
|
|
|
|
bool is_NSString = false;
|
|
|
|
bool is_strftime = false;
|
2008-09-26 11:32:58 +08:00
|
|
|
bool is_CFString = false;
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-06-27 02:38:35 +08:00
|
|
|
switch (FormatLen) {
|
|
|
|
default: break;
|
2008-06-29 08:43:07 +08:00
|
|
|
case 5: Supported = !memcmp(Format, "scanf", 5); break;
|
|
|
|
case 6: Supported = !memcmp(Format, "printf", 6); break;
|
2009-08-06 11:00:50 +08:00
|
|
|
case 7: Supported = !memcmp(Format, "printf0", 7) ||
|
|
|
|
!memcmp(Format, "strfmon", 7); break;
|
2008-06-27 02:38:35 +08:00
|
|
|
case 8:
|
2008-09-26 11:32:58 +08:00
|
|
|
Supported = (is_strftime = !memcmp(Format, "strftime", 8)) ||
|
|
|
|
(is_NSString = !memcmp(Format, "NSString", 8)) ||
|
|
|
|
(is_CFString = !memcmp(Format, "CFString", 8));
|
2008-06-27 02:38:35 +08:00
|
|
|
break;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-06-27 02:38:35 +08:00
|
|
|
if (!Supported) {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported)
|
|
|
|
<< "format" << Attr.getParameterName()->getName();
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// checks for the 2nd argument
|
2008-06-29 07:36:30 +08:00
|
|
|
Expr *IdxExpr = static_cast<Expr *>(Attr.getArg(0));
|
2008-06-29 08:43:07 +08:00
|
|
|
llvm::APSInt Idx(32);
|
|
|
|
if (!IdxExpr->isIntegerConstantExpr(Idx, S.Context)) {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
|
2008-11-19 16:23:25 +08:00
|
|
|
<< "format" << 2 << IdxExpr->getSourceRange();
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Idx.getZExtValue() < FirstIdx || Idx.getZExtValue() > NumArgs) {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
|
2008-11-19 16:23:25 +08:00
|
|
|
<< "format" << 2 << IdxExpr->getSourceRange();
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: Do we need to bounds check?
|
|
|
|
unsigned ArgIdx = Idx.getZExtValue() - 1;
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-06-27 02:38:35 +08:00
|
|
|
// make sure the format string is really a string
|
2008-09-26 12:12:28 +08:00
|
|
|
QualType Ty = getFunctionOrMethodArgType(d, ArgIdx);
|
2008-06-27 02:38:35 +08:00
|
|
|
|
2008-09-26 11:32:58 +08:00
|
|
|
if (is_CFString) {
|
|
|
|
if (!isCFStringType(Ty, S.Context)) {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_format_attribute_not)
|
|
|
|
<< "a CFString" << IdxExpr->getSourceRange();
|
2008-09-26 11:32:58 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else if (is_NSString) {
|
2009-05-16 15:39:55 +08:00
|
|
|
// FIXME: do we need to check if the type is NSString*? What are the
|
|
|
|
// semantics?
|
2008-06-29 08:43:07 +08:00
|
|
|
if (!isNSStringType(Ty, S.Context)) {
|
2009-05-16 15:39:55 +08:00
|
|
|
// FIXME: Should highlight the actual expression that has the wrong type.
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_format_attribute_not)
|
|
|
|
<< "an NSString" << IdxExpr->getSourceRange();
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
2009-07-25 03:02:52 +08:00
|
|
|
}
|
2008-06-27 02:38:35 +08:00
|
|
|
} else if (!Ty->isPointerType() ||
|
2009-07-30 05:53:49 +08:00
|
|
|
!Ty->getAs<PointerType>()->getPointeeType()->isCharType()) {
|
2009-05-16 15:39:55 +08:00
|
|
|
// FIXME: Should highlight the actual expression that has the wrong type.
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_format_attribute_not)
|
|
|
|
<< "a string type" << IdxExpr->getSourceRange();
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// check the 3rd argument
|
2008-06-29 07:36:30 +08:00
|
|
|
Expr *FirstArgExpr = static_cast<Expr *>(Attr.getArg(1));
|
2008-06-29 08:43:07 +08:00
|
|
|
llvm::APSInt FirstArg(32);
|
|
|
|
if (!FirstArgExpr->isIntegerConstantExpr(FirstArg, S.Context)) {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
|
2008-11-19 16:23:25 +08:00
|
|
|
<< "format" << 3 << FirstArgExpr->getSourceRange();
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// check if the function is variadic if the 3rd argument non-zero
|
|
|
|
if (FirstArg != 0) {
|
2008-09-26 12:12:28 +08:00
|
|
|
if (isFunctionOrMethodVariadic(d)) {
|
2008-06-27 02:38:35 +08:00
|
|
|
++NumArgs; // +1 for ...
|
|
|
|
} else {
|
2008-06-29 08:43:07 +08:00
|
|
|
S.Diag(d->getLocation(), diag::err_format_attribute_requires_variadic);
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-19 16:23:25 +08:00
|
|
|
// strftime requires FirstArg to be 0 because it doesn't read from any
|
|
|
|
// variable the input is just the current time + the format string.
|
2008-06-27 02:38:35 +08:00
|
|
|
if (is_strftime) {
|
|
|
|
if (FirstArg != 0) {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_format_strftime_third_parameter)
|
|
|
|
<< FirstArgExpr->getSourceRange();
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
// if 0 it disables parameter checking (to use with e.g. va_list)
|
|
|
|
} else if (FirstArg != 0 && FirstArg != NumArgs) {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
|
2008-11-19 16:23:25 +08:00
|
|
|
<< "format" << 3 << FirstArgExpr->getSourceRange();
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
d->addAttr(::new (S.Context) FormatAttr(std::string(Format, FormatLen),
|
2008-06-27 02:38:35 +08:00
|
|
|
Idx.getZExtValue(), FirstArg.getZExtValue()));
|
|
|
|
}
|
|
|
|
|
2008-06-29 08:28:59 +08:00
|
|
|
static void HandleTransparentUnionAttr(Decl *d, const AttributeList &Attr,
|
|
|
|
Sema &S) {
|
2008-06-27 02:38:35 +08:00
|
|
|
// check the attribute arguments.
|
2008-06-29 07:36:30 +08:00
|
|
|
if (Attr.getNumArgs() != 0) {
|
2008-11-19 16:23:25 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-04-30 06:16:16 +08:00
|
|
|
// Try to find the underlying union declaration.
|
|
|
|
RecordDecl *RD = 0;
|
2008-09-02 13:19:23 +08:00
|
|
|
TypedefDecl *TD = dyn_cast<TypedefDecl>(d);
|
2009-04-30 06:16:16 +08:00
|
|
|
if (TD && TD->getUnderlyingType()->isUnionType())
|
|
|
|
RD = TD->getUnderlyingType()->getAsUnionType()->getDecl();
|
|
|
|
else
|
|
|
|
RD = dyn_cast<RecordDecl>(d);
|
|
|
|
|
|
|
|
if (!RD || !RD->isUnion()) {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
2009-05-14 05:07:32 +08:00
|
|
|
<< Attr.getName() << 1 /*union*/;
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-04-30 06:16:16 +08:00
|
|
|
if (!RD->isDefinition()) {
|
2009-07-25 03:02:52 +08:00
|
|
|
S.Diag(Attr.getLoc(),
|
2009-04-30 06:16:16 +08:00
|
|
|
diag::warn_transparent_union_attribute_not_definition);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-06-30 10:36:12 +08:00
|
|
|
RecordDecl::field_iterator Field = RD->field_begin(),
|
|
|
|
FieldEnd = RD->field_end();
|
2009-04-30 06:16:16 +08:00
|
|
|
if (Field == FieldEnd) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::warn_transparent_union_attribute_zero_fields);
|
|
|
|
return;
|
|
|
|
}
|
2008-09-02 13:19:23 +08:00
|
|
|
|
2009-04-30 06:16:16 +08:00
|
|
|
FieldDecl *FirstField = *Field;
|
|
|
|
QualType FirstType = FirstField->getType();
|
|
|
|
if (FirstType->isFloatingType() || FirstType->isVectorType()) {
|
2009-07-25 03:02:52 +08:00
|
|
|
S.Diag(FirstField->getLocation(),
|
2009-04-30 06:16:16 +08:00
|
|
|
diag::warn_transparent_union_attribute_floating);
|
|
|
|
return;
|
|
|
|
}
|
2008-09-02 13:19:23 +08:00
|
|
|
|
2009-04-30 06:16:16 +08:00
|
|
|
uint64_t FirstSize = S.Context.getTypeSize(FirstType);
|
|
|
|
uint64_t FirstAlign = S.Context.getTypeAlign(FirstType);
|
|
|
|
for (; Field != FieldEnd; ++Field) {
|
|
|
|
QualType FieldType = Field->getType();
|
|
|
|
if (S.Context.getTypeSize(FieldType) != FirstSize ||
|
|
|
|
S.Context.getTypeAlign(FieldType) != FirstAlign) {
|
|
|
|
// Warn if we drop the attribute.
|
|
|
|
bool isSize = S.Context.getTypeSize(FieldType) != FirstSize;
|
2009-07-25 03:02:52 +08:00
|
|
|
unsigned FieldBits = isSize? S.Context.getTypeSize(FieldType)
|
2009-04-30 06:16:16 +08:00
|
|
|
: S.Context.getTypeAlign(FieldType);
|
2009-07-25 03:02:52 +08:00
|
|
|
S.Diag(Field->getLocation(),
|
2009-04-30 06:16:16 +08:00
|
|
|
diag::warn_transparent_union_attribute_field_size_align)
|
|
|
|
<< isSize << Field->getDeclName() << FieldBits;
|
|
|
|
unsigned FirstBits = isSize? FirstSize : FirstAlign;
|
2009-07-25 03:02:52 +08:00
|
|
|
S.Diag(FirstField->getLocation(),
|
2009-04-30 06:16:16 +08:00
|
|
|
diag::note_transparent_union_first_field_size_align)
|
|
|
|
<< isSize << FirstBits;
|
2008-09-02 13:19:23 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2008-06-27 02:38:35 +08:00
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
RD->addAttr(::new (S.Context) TransparentUnionAttr());
|
2008-06-27 02:38:35 +08:00
|
|
|
}
|
|
|
|
|
2008-06-29 08:28:59 +08:00
|
|
|
static void HandleAnnotateAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
2008-06-27 02:38:35 +08:00
|
|
|
// check the attribute arguments.
|
2008-06-29 07:36:30 +08:00
|
|
|
if (Attr.getNumArgs() != 1) {
|
2008-11-19 16:23:25 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-08-11 03:03:04 +08:00
|
|
|
Expr *ArgExpr = static_cast<Expr *>(Attr.getArg(0));
|
|
|
|
StringLiteral *SE = dyn_cast<StringLiteral>(ArgExpr);
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-06-27 02:38:35 +08:00
|
|
|
// Make sure that there is a string literal as the annotation's single
|
|
|
|
// argument.
|
|
|
|
if (!SE) {
|
2009-08-11 03:03:04 +08:00
|
|
|
S.Diag(ArgExpr->getLocStart(), diag::err_attribute_not_string) <<"annotate";
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-06-30 10:34:44 +08:00
|
|
|
d->addAttr(::new (S.Context) AnnotateAttr(std::string(SE->getStrData(),
|
2009-03-04 14:34:08 +08:00
|
|
|
SE->getByteLength())));
|
2008-06-27 02:38:35 +08:00
|
|
|
}
|
|
|
|
|
2008-06-29 08:43:07 +08:00
|
|
|
static void HandleAlignedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
2008-06-27 02:38:35 +08:00
|
|
|
// check the attribute arguments.
|
2008-06-29 07:36:30 +08:00
|
|
|
if (Attr.getNumArgs() > 1) {
|
2008-11-19 16:23:25 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned Align = 0;
|
2008-06-29 07:36:30 +08:00
|
|
|
if (Attr.getNumArgs() == 0) {
|
2008-06-27 02:38:35 +08:00
|
|
|
// FIXME: This should be the target specific maximum alignment.
|
2009-02-19 04:06:09 +08:00
|
|
|
// (For now we just use 128 bits which is the maximum on X86).
|
2008-06-27 02:38:35 +08:00
|
|
|
Align = 128;
|
2009-06-30 10:34:44 +08:00
|
|
|
d->addAttr(::new (S.Context) AlignedAttr(Align));
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-06-29 07:50:44 +08:00
|
|
|
Expr *alignmentExpr = static_cast<Expr *>(Attr.getArg(0));
|
|
|
|
llvm::APSInt Alignment(32);
|
2008-06-29 08:43:07 +08:00
|
|
|
if (!alignmentExpr->isIntegerConstantExpr(Alignment, S.Context)) {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
|
|
|
|
<< "aligned" << alignmentExpr->getSourceRange();
|
2008-06-29 07:50:44 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-02-17 07:37:57 +08:00
|
|
|
if (!llvm::isPowerOf2_64(Alignment.getZExtValue())) {
|
2009-07-25 03:02:52 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_aligned_not_power_of_two)
|
2009-02-17 07:37:57 +08:00
|
|
|
<< alignmentExpr->getSourceRange();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
d->addAttr(::new (S.Context) AlignedAttr(Alignment.getZExtValue() * 8));
|
2008-06-27 02:38:35 +08:00
|
|
|
}
|
2008-06-28 06:18:37 +08:00
|
|
|
|
2009-07-25 03:02:52 +08:00
|
|
|
/// HandleModeAttr - This attribute modifies the width of a decl with primitive
|
|
|
|
/// type.
|
2008-06-28 06:18:37 +08:00
|
|
|
///
|
2009-07-25 03:02:52 +08:00
|
|
|
/// Despite what would be logical, the mode attribute is a decl attribute, not a
|
|
|
|
/// type attribute: 'int ** __attribute((mode(HI))) *G;' tries to make 'G' be
|
|
|
|
/// HImode, not an intermediate pointer.
|
2008-06-29 08:28:59 +08:00
|
|
|
static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
|
2008-06-28 06:18:37 +08:00
|
|
|
// This attribute isn't documented, but glibc uses it. It changes
|
|
|
|
// the width of an int or unsigned int to the specified size.
|
|
|
|
|
|
|
|
// Check that there aren't any arguments
|
|
|
|
if (Attr.getNumArgs() != 0) {
|
2008-11-19 16:23:25 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
|
2008-06-28 06:18:37 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
IdentifierInfo *Name = Attr.getParameterName();
|
|
|
|
if (!Name) {
|
2008-06-29 08:28:59 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_missing_parameter_name);
|
2008-06-28 06:18:37 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
const char *Str = Name->getName();
|
|
|
|
unsigned Len = Name->getLength();
|
|
|
|
|
|
|
|
// Normalize the attribute name, __foo__ becomes foo.
|
|
|
|
if (Len > 4 && Str[0] == '_' && Str[1] == '_' &&
|
|
|
|
Str[Len - 2] == '_' && Str[Len - 1] == '_') {
|
|
|
|
Str += 2;
|
|
|
|
Len -= 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned DestWidth = 0;
|
|
|
|
bool IntegerMode = true;
|
2009-03-03 14:41:03 +08:00
|
|
|
bool ComplexMode = false;
|
2008-06-28 06:18:37 +08:00
|
|
|
switch (Len) {
|
|
|
|
case 2:
|
2009-03-03 14:41:03 +08:00
|
|
|
switch (Str[0]) {
|
|
|
|
case 'Q': DestWidth = 8; break;
|
|
|
|
case 'H': DestWidth = 16; break;
|
|
|
|
case 'S': DestWidth = 32; break;
|
|
|
|
case 'D': DestWidth = 64; break;
|
|
|
|
case 'X': DestWidth = 96; break;
|
|
|
|
case 'T': DestWidth = 128; break;
|
|
|
|
}
|
|
|
|
if (Str[1] == 'F') {
|
|
|
|
IntegerMode = false;
|
|
|
|
} else if (Str[1] == 'C') {
|
|
|
|
IntegerMode = false;
|
|
|
|
ComplexMode = true;
|
|
|
|
} else if (Str[1] != 'I') {
|
|
|
|
DestWidth = 0;
|
|
|
|
}
|
2008-06-28 06:18:37 +08:00
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
// FIXME: glibc uses 'word' to define register_t; this is narrower than a
|
|
|
|
// pointer on PIC16 and other embedded platforms.
|
|
|
|
if (!memcmp(Str, "word", 4))
|
2008-06-29 08:28:59 +08:00
|
|
|
DestWidth = S.Context.Target.getPointerWidth(0);
|
2008-06-28 06:18:37 +08:00
|
|
|
if (!memcmp(Str, "byte", 4))
|
2008-06-29 08:28:59 +08:00
|
|
|
DestWidth = S.Context.Target.getCharWidth();
|
2008-06-28 06:18:37 +08:00
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
if (!memcmp(Str, "pointer", 7))
|
2008-06-29 08:28:59 +08:00
|
|
|
DestWidth = S.Context.Target.getPointerWidth(0);
|
2008-06-28 06:18:37 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
QualType OldTy;
|
|
|
|
if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D))
|
|
|
|
OldTy = TD->getUnderlyingType();
|
|
|
|
else if (ValueDecl *VD = dyn_cast<ValueDecl>(D))
|
|
|
|
OldTy = VD->getType();
|
|
|
|
else {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(D->getLocation(), diag::err_attr_wrong_decl)
|
|
|
|
<< "mode" << SourceRange(Attr.getLoc(), Attr.getLoc());
|
2008-06-28 06:18:37 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-03-03 14:41:03 +08:00
|
|
|
|
|
|
|
if (!OldTy->getAsBuiltinType() && !OldTy->isComplexType())
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_mode_not_primitive);
|
|
|
|
else if (IntegerMode) {
|
|
|
|
if (!OldTy->isIntegralType())
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_mode_wrong_type);
|
|
|
|
} else if (ComplexMode) {
|
|
|
|
if (!OldTy->isComplexType())
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_mode_wrong_type);
|
|
|
|
} else {
|
|
|
|
if (!OldTy->isFloatingType())
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_mode_wrong_type);
|
|
|
|
}
|
|
|
|
|
2009-05-16 15:39:55 +08:00
|
|
|
// FIXME: Sync this with InitializePredefinedMacros; we need to match int8_t
|
|
|
|
// and friends, at least with glibc.
|
|
|
|
// FIXME: Make sure 32/64-bit integers don't get defined to types of the wrong
|
|
|
|
// width on unusual platforms.
|
2009-02-13 10:31:07 +08:00
|
|
|
// FIXME: Make sure floating-point mappings are accurate
|
|
|
|
// FIXME: Support XF and TF types
|
2008-06-28 06:18:37 +08:00
|
|
|
QualType NewTy;
|
|
|
|
switch (DestWidth) {
|
|
|
|
case 0:
|
2008-11-19 16:23:25 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_unknown_machine_mode) << Name;
|
2008-06-28 06:18:37 +08:00
|
|
|
return;
|
|
|
|
default:
|
2008-11-19 16:23:25 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_unsupported_machine_mode) << Name;
|
2008-06-28 06:18:37 +08:00
|
|
|
return;
|
|
|
|
case 8:
|
2009-03-03 14:41:03 +08:00
|
|
|
if (!IntegerMode) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_unsupported_machine_mode) << Name;
|
|
|
|
return;
|
|
|
|
}
|
2008-06-28 06:18:37 +08:00
|
|
|
if (OldTy->isSignedIntegerType())
|
2008-06-29 08:28:59 +08:00
|
|
|
NewTy = S.Context.SignedCharTy;
|
2008-06-28 06:18:37 +08:00
|
|
|
else
|
2008-06-29 08:28:59 +08:00
|
|
|
NewTy = S.Context.UnsignedCharTy;
|
2008-06-28 06:18:37 +08:00
|
|
|
break;
|
|
|
|
case 16:
|
2009-03-03 14:41:03 +08:00
|
|
|
if (!IntegerMode) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_unsupported_machine_mode) << Name;
|
|
|
|
return;
|
|
|
|
}
|
2008-06-28 06:18:37 +08:00
|
|
|
if (OldTy->isSignedIntegerType())
|
2008-06-29 08:28:59 +08:00
|
|
|
NewTy = S.Context.ShortTy;
|
2008-06-28 06:18:37 +08:00
|
|
|
else
|
2008-06-29 08:28:59 +08:00
|
|
|
NewTy = S.Context.UnsignedShortTy;
|
2008-06-28 06:18:37 +08:00
|
|
|
break;
|
|
|
|
case 32:
|
|
|
|
if (!IntegerMode)
|
2008-06-29 08:28:59 +08:00
|
|
|
NewTy = S.Context.FloatTy;
|
2008-06-28 06:18:37 +08:00
|
|
|
else if (OldTy->isSignedIntegerType())
|
2008-06-29 08:28:59 +08:00
|
|
|
NewTy = S.Context.IntTy;
|
2008-06-28 06:18:37 +08:00
|
|
|
else
|
2008-06-29 08:28:59 +08:00
|
|
|
NewTy = S.Context.UnsignedIntTy;
|
2008-06-28 06:18:37 +08:00
|
|
|
break;
|
|
|
|
case 64:
|
|
|
|
if (!IntegerMode)
|
2008-06-29 08:28:59 +08:00
|
|
|
NewTy = S.Context.DoubleTy;
|
2008-06-28 06:18:37 +08:00
|
|
|
else if (OldTy->isSignedIntegerType())
|
2008-06-29 08:28:59 +08:00
|
|
|
NewTy = S.Context.LongLongTy;
|
2008-06-28 06:18:37 +08:00
|
|
|
else
|
2008-06-29 08:28:59 +08:00
|
|
|
NewTy = S.Context.UnsignedLongLongTy;
|
2008-06-28 06:18:37 +08:00
|
|
|
break;
|
2009-03-03 14:41:03 +08:00
|
|
|
case 96:
|
|
|
|
NewTy = S.Context.LongDoubleTy;
|
|
|
|
break;
|
2009-02-13 10:31:07 +08:00
|
|
|
case 128:
|
|
|
|
if (!IntegerMode) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_unsupported_machine_mode) << Name;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
NewTy = S.Context.getFixedWidthIntType(128, OldTy->isSignedIntegerType());
|
2009-03-03 14:41:03 +08:00
|
|
|
break;
|
2008-06-28 06:18:37 +08:00
|
|
|
}
|
|
|
|
|
2009-03-03 14:41:03 +08:00
|
|
|
if (ComplexMode) {
|
|
|
|
NewTy = S.Context.getComplexType(NewTy);
|
2008-06-28 06:18:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Install the new type.
|
|
|
|
if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D))
|
|
|
|
TD->setUnderlyingType(NewTy);
|
|
|
|
else
|
|
|
|
cast<ValueDecl>(D)->setType(NewTy);
|
|
|
|
}
|
2008-06-29 08:23:49 +08:00
|
|
|
|
2009-02-13 14:46:13 +08:00
|
|
|
static void HandleNodebugAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
|
|
|
// check the attribute arguments.
|
|
|
|
if (Attr.getNumArgs() > 0) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
|
|
|
|
return;
|
|
|
|
}
|
2009-02-13 16:11:52 +08:00
|
|
|
|
2009-02-20 03:16:48 +08:00
|
|
|
if (!isFunctionOrMethod(d)) {
|
2009-02-13 14:46:13 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
2009-05-14 05:07:32 +08:00
|
|
|
<< Attr.getName() << 0 /*function*/;
|
2009-02-13 14:46:13 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
d->addAttr(::new (S.Context) NodebugAttr());
|
2009-02-13 14:46:13 +08:00
|
|
|
}
|
|
|
|
|
2009-02-20 03:16:48 +08:00
|
|
|
static void HandleNoinlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
|
|
|
// check the attribute arguments.
|
|
|
|
if (Attr.getNumArgs() != 0) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
|
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-04-15 01:02:11 +08:00
|
|
|
if (!isa<FunctionDecl>(d)) {
|
2009-02-20 03:16:48 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
2009-05-14 05:07:32 +08:00
|
|
|
<< Attr.getName() << 0 /*function*/;
|
2009-02-20 03:16:48 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
d->addAttr(::new (S.Context) NoinlineAttr());
|
2009-02-20 03:16:48 +08:00
|
|
|
}
|
|
|
|
|
2009-04-21 03:12:28 +08:00
|
|
|
static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
2009-04-15 00:30:50 +08:00
|
|
|
// check the attribute arguments.
|
|
|
|
if (Attr.getNumArgs() != 0) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
|
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-04-15 01:02:11 +08:00
|
|
|
FunctionDecl *Fn = dyn_cast<FunctionDecl>(d);
|
|
|
|
if (Fn == 0) {
|
2009-04-15 00:30:50 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
2009-05-14 05:07:32 +08:00
|
|
|
<< Attr.getName() << 0 /*function*/;
|
2009-04-15 00:30:50 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-04-15 01:02:11 +08:00
|
|
|
if (!Fn->isInline()) {
|
2009-04-21 03:12:28 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::warn_gnu_inline_attribute_requires_inline);
|
2009-04-15 01:02:11 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
d->addAttr(::new (S.Context) GNUInlineAttr());
|
2009-04-15 00:30:50 +08:00
|
|
|
}
|
|
|
|
|
2009-03-28 02:38:55 +08:00
|
|
|
static void HandleRegparmAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
|
|
|
// check the attribute arguments.
|
|
|
|
if (Attr.getNumArgs() != 1) {
|
2009-03-28 05:06:47 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
|
2009-03-28 02:38:55 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-03-28 05:06:47 +08:00
|
|
|
|
2009-03-28 02:38:55 +08:00
|
|
|
if (!isFunctionOrMethod(d)) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
2009-05-14 05:07:32 +08:00
|
|
|
<< Attr.getName() << 0 /*function*/;
|
2009-03-28 02:38:55 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-03-28 05:06:47 +08:00
|
|
|
|
|
|
|
Expr *NumParamsExpr = static_cast<Expr *>(Attr.getArg(0));
|
|
|
|
llvm::APSInt NumParams(32);
|
|
|
|
if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
|
|
|
|
<< "regparm" << NumParamsExpr->getSourceRange();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-04-04 07:38:25 +08:00
|
|
|
if (S.Context.Target.getRegParmMax() == 0) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_regparm_wrong_platform)
|
2009-03-28 05:06:47 +08:00
|
|
|
<< NumParamsExpr->getSourceRange();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-04-04 18:27:50 +08:00
|
|
|
if (NumParams.getLimitedValue(255) > S.Context.Target.getRegParmMax()) {
|
2009-04-04 07:38:25 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_regparm_invalid_number)
|
|
|
|
<< S.Context.Target.getRegParmMax() << NumParamsExpr->getSourceRange();
|
2009-03-28 05:06:47 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
d->addAttr(::new (S.Context) RegparmAttr(NumParams.getZExtValue()));
|
2009-03-28 02:38:55 +08:00
|
|
|
}
|
|
|
|
|
2009-05-09 10:44:38 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Checker-specific attribute handlers.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &Attr,
|
|
|
|
Sema &S) {
|
|
|
|
|
2009-05-14 05:07:32 +08:00
|
|
|
QualType RetTy;
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-05-14 05:07:32 +08:00
|
|
|
if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(d))
|
|
|
|
RetTy = MD->getResultType();
|
|
|
|
else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(d))
|
|
|
|
RetTy = FD->getResultType();
|
|
|
|
else {
|
2009-08-20 07:56:48 +08:00
|
|
|
SourceLocation L = Attr.getLoc();
|
|
|
|
S.Diag(d->getLocStart(), diag::warn_attribute_wrong_decl_type)
|
|
|
|
<< SourceRange(L, L) << Attr.getName() << 3 /* function or method */;
|
2009-05-09 10:44:38 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-07-30 05:53:49 +08:00
|
|
|
if (!(S.Context.isObjCNSObjectType(RetTy) || RetTy->getAs<PointerType>()
|
2009-07-11 07:34:53 +08:00
|
|
|
|| RetTy->getAsObjCObjectPointerType())) {
|
2009-08-20 07:56:48 +08:00
|
|
|
SourceLocation L = Attr.getLoc();
|
|
|
|
S.Diag(d->getLocStart(), diag::warn_ns_attribute_wrong_return_type)
|
|
|
|
<< SourceRange(L, L) << Attr.getName();
|
2009-07-25 03:02:52 +08:00
|
|
|
return;
|
2009-05-14 05:07:32 +08:00
|
|
|
}
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2009-05-09 10:44:38 +08:00
|
|
|
switch (Attr.getKind()) {
|
|
|
|
default:
|
|
|
|
assert(0 && "invalid ownership attribute");
|
|
|
|
return;
|
|
|
|
case AttributeList::AT_cf_returns_retained:
|
2009-06-30 10:34:44 +08:00
|
|
|
d->addAttr(::new (S.Context) CFReturnsRetainedAttr());
|
2009-05-09 10:44:38 +08:00
|
|
|
return;
|
|
|
|
case AttributeList::AT_ns_returns_retained:
|
2009-06-30 10:34:44 +08:00
|
|
|
d->addAttr(::new (S.Context) NSReturnsRetainedAttr());
|
2009-05-09 10:44:38 +08:00
|
|
|
return;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2008-06-29 08:23:49 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Top Level Sema Entry Points
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2008-12-22 03:24:58 +08:00
|
|
|
/// ProcessDeclAttribute - Apply the specific attribute to the specified decl if
|
2008-06-29 08:43:07 +08:00
|
|
|
/// the attribute applies to decls. If the attribute is a type attribute, just
|
|
|
|
/// silently ignore it.
|
2009-07-25 03:02:52 +08:00
|
|
|
static void ProcessDeclAttribute(Scope *scope, Decl *D,
|
|
|
|
const AttributeList &Attr, Sema &S) {
|
2009-06-09 07:27:34 +08:00
|
|
|
if (Attr.isDeclspecAttribute())
|
|
|
|
// FIXME: Try to deal with __declspec attributes!
|
|
|
|
return;
|
2008-06-29 08:43:07 +08:00
|
|
|
switch (Attr.getKind()) {
|
2008-08-01 06:40:48 +08:00
|
|
|
case AttributeList::AT_IBOutlet: HandleIBOutletAttr (D, Attr, S); break;
|
2008-06-29 08:43:07 +08:00
|
|
|
case AttributeList::AT_address_space:
|
2009-02-19 01:52:36 +08:00
|
|
|
case AttributeList::AT_objc_gc:
|
2009-07-25 03:02:52 +08:00
|
|
|
// Ignore these, these are type attributes, handled by
|
|
|
|
// ProcessTypeAttributes.
|
2008-06-29 08:43:07 +08:00
|
|
|
break;
|
|
|
|
case AttributeList::AT_alias: HandleAliasAttr (D, Attr, S); break;
|
2008-08-01 06:40:48 +08:00
|
|
|
case AttributeList::AT_aligned: HandleAlignedAttr (D, Attr, S); break;
|
2009-07-25 03:02:52 +08:00
|
|
|
case AttributeList::AT_always_inline:
|
2008-10-28 08:17:57 +08:00
|
|
|
HandleAlwaysInlineAttr (D, Attr, S); break;
|
2009-04-10 08:01:14 +08:00
|
|
|
case AttributeList::AT_analyzer_noreturn:
|
2009-07-25 03:02:52 +08:00
|
|
|
HandleAnalyzerNoReturnAttr (D, Attr, S); break;
|
2008-08-01 06:40:48 +08:00
|
|
|
case AttributeList::AT_annotate: HandleAnnotateAttr (D, Attr, S); break;
|
|
|
|
case AttributeList::AT_constructor: HandleConstructorAttr(D, Attr, S); break;
|
2008-06-29 08:43:07 +08:00
|
|
|
case AttributeList::AT_deprecated: HandleDeprecatedAttr(D, Attr, S); break;
|
2008-08-01 06:40:48 +08:00
|
|
|
case AttributeList::AT_destructor: HandleDestructorAttr(D, Attr, S); break;
|
2008-06-29 08:43:07 +08:00
|
|
|
case AttributeList::AT_dllexport: HandleDLLExportAttr (D, Attr, S); break;
|
2008-08-01 06:40:48 +08:00
|
|
|
case AttributeList::AT_dllimport: HandleDLLImportAttr (D, Attr, S); break;
|
|
|
|
case AttributeList::AT_ext_vector_type:
|
2009-06-18 05:51:59 +08:00
|
|
|
HandleExtVectorTypeAttr(scope, D, Attr, S);
|
2008-08-01 06:40:48 +08:00
|
|
|
break;
|
2008-06-29 08:43:07 +08:00
|
|
|
case AttributeList::AT_fastcall: HandleFastCallAttr (D, Attr, S); break;
|
|
|
|
case AttributeList::AT_format: HandleFormatAttr (D, Attr, S); break;
|
2009-05-21 01:41:43 +08:00
|
|
|
case AttributeList::AT_format_arg: HandleFormatArgAttr (D, Attr, S); break;
|
2009-04-21 03:12:28 +08:00
|
|
|
case AttributeList::AT_gnu_inline: HandleGNUInlineAttr(D, Attr, S); break;
|
2008-08-01 06:40:48 +08:00
|
|
|
case AttributeList::AT_mode: HandleModeAttr (D, Attr, S); break;
|
2009-08-10 04:07:29 +08:00
|
|
|
case AttributeList::AT_malloc: HandleMallocAttr (D, Attr, S); break;
|
2008-07-22 05:53:04 +08:00
|
|
|
case AttributeList::AT_nonnull: HandleNonNullAttr (D, Attr, S); break;
|
2008-08-01 06:40:48 +08:00
|
|
|
case AttributeList::AT_noreturn: HandleNoReturnAttr (D, Attr, S); break;
|
|
|
|
case AttributeList::AT_nothrow: HandleNothrowAttr (D, Attr, S); break;
|
2009-05-09 10:44:38 +08:00
|
|
|
|
|
|
|
// Checker-specific.
|
|
|
|
case AttributeList::AT_ns_returns_retained:
|
|
|
|
case AttributeList::AT_cf_returns_retained:
|
|
|
|
HandleNSReturnsRetainedAttr(D, Attr, S); break;
|
|
|
|
|
2009-06-26 14:32:41 +08:00
|
|
|
case AttributeList::AT_reqd_wg_size:
|
|
|
|
HandleReqdWorkGroupSize(D, Attr, S); break;
|
|
|
|
|
2008-08-01 06:40:48 +08:00
|
|
|
case AttributeList::AT_packed: HandlePackedAttr (D, Attr, S); break;
|
2009-02-13 01:28:23 +08:00
|
|
|
case AttributeList::AT_section: HandleSectionAttr (D, Attr, S); break;
|
2008-08-01 06:40:48 +08:00
|
|
|
case AttributeList::AT_stdcall: HandleStdCallAttr (D, Attr, S); break;
|
2008-12-17 09:07:27 +08:00
|
|
|
case AttributeList::AT_unavailable: HandleUnavailableAttr(D, Attr, S); break;
|
2008-07-25 12:39:19 +08:00
|
|
|
case AttributeList::AT_unused: HandleUnusedAttr (D, Attr, S); break;
|
2009-02-14 03:23:53 +08:00
|
|
|
case AttributeList::AT_used: HandleUsedAttr (D, Attr, S); break;
|
2008-08-01 06:40:48 +08:00
|
|
|
case AttributeList::AT_vector_size: HandleVectorSizeAttr(D, Attr, S); break;
|
|
|
|
case AttributeList::AT_visibility: HandleVisibilityAttr(D, Attr, S); break;
|
2009-02-14 15:37:35 +08:00
|
|
|
case AttributeList::AT_warn_unused_result: HandleWarnUnusedResult(D,Attr,S);
|
|
|
|
break;
|
2008-08-01 06:40:48 +08:00
|
|
|
case AttributeList::AT_weak: HandleWeakAttr (D, Attr, S); break;
|
2009-03-06 14:39:57 +08:00
|
|
|
case AttributeList::AT_weak_import: HandleWeakImportAttr(D, Attr, S); break;
|
2008-06-29 08:43:07 +08:00
|
|
|
case AttributeList::AT_transparent_union:
|
|
|
|
HandleTransparentUnionAttr(D, Attr, S);
|
|
|
|
break;
|
2009-02-14 16:09:34 +08:00
|
|
|
case AttributeList::AT_objc_exception:
|
|
|
|
HandleObjCExceptionAttr(D, Attr, S);
|
|
|
|
break;
|
Initial implementation of function overloading in C.
This commit adds a new attribute, "overloadable", that enables C++
function overloading in C. The attribute can only be added to function
declarations, e.g.,
int *f(int) __attribute__((overloadable));
If the "overloadable" attribute exists on a function with a given
name, *all* functions with that name (and in that scope) must have the
"overloadable" attribute. Sets of overloaded functions with the
"overloadable" attribute then follow the normal C++ rules for
overloaded functions, e.g., overloads must have different
parameter-type-lists from each other.
When calling an overloaded function in C, we follow the same
overloading rules as C++, with three extensions to the set of standard
conversions:
- A value of a given struct or union type T can be converted to the
type T. This is just the identity conversion. (In C++, this would
go through a copy constructor).
- A value of pointer type T* can be converted to a value of type U*
if T and U are compatible types. This conversion has Conversion
rank (it's considered a pointer conversion in C).
- A value of type T can be converted to a value of type U if T and U
are compatible (and are not both pointer types). This conversion
has Conversion rank (it's considered to be a new kind of
conversion unique to C, a "compatible" conversion).
Known defects (and, therefore, next steps):
1) The standard-conversion handling does not understand conversions
involving _Complex or vector extensions, so it is likely to get
these wrong. We need to add these conversions.
2) All overloadable functions with the same name will have the same
linkage name, which means we'll get a collision in the linker (if
not sooner). We'll need to mangle the names of these functions.
llvm-svn: 64336
2009-02-12 07:02:49 +08:00
|
|
|
case AttributeList::AT_overloadable:HandleOverloadableAttr(D, Attr, S); break;
|
2009-01-14 07:34:40 +08:00
|
|
|
case AttributeList::AT_nsobject: HandleObjCNSObject (D, Attr, S); break;
|
2008-09-19 00:44:58 +08:00
|
|
|
case AttributeList::AT_blocks: HandleBlocksAttr (D, Attr, S); break;
|
2008-10-06 02:05:59 +08:00
|
|
|
case AttributeList::AT_sentinel: HandleSentinelAttr (D, Attr, S); break;
|
2008-10-06 07:32:53 +08:00
|
|
|
case AttributeList::AT_const: HandleConstAttr (D, Attr, S); break;
|
|
|
|
case AttributeList::AT_pure: HandlePureAttr (D, Attr, S); break;
|
2009-01-31 09:16:18 +08:00
|
|
|
case AttributeList::AT_cleanup: HandleCleanupAttr (D, Attr, S); break;
|
2009-02-13 14:46:13 +08:00
|
|
|
case AttributeList::AT_nodebug: HandleNodebugAttr (D, Attr, S); break;
|
2009-02-20 03:16:48 +08:00
|
|
|
case AttributeList::AT_noinline: HandleNoinlineAttr (D, Attr, S); break;
|
2009-03-28 05:06:47 +08:00
|
|
|
case AttributeList::AT_regparm: HandleRegparmAttr (D, Attr, S); break;
|
2009-07-25 03:02:52 +08:00
|
|
|
case AttributeList::IgnoredAttribute:
|
2009-04-26 02:44:54 +08:00
|
|
|
case AttributeList::AT_no_instrument_function: // Interacts with -pg.
|
2009-02-13 16:16:43 +08:00
|
|
|
// Just ignore
|
|
|
|
break;
|
2008-06-29 08:43:07 +08:00
|
|
|
default:
|
2009-02-13 14:46:13 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
|
2008-06-29 08:43:07 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ProcessDeclAttributeList - Apply all the decl attributes in the specified
|
|
|
|
/// attribute list to the specified decl, ignoring any type attributes.
|
2009-06-18 05:51:59 +08:00
|
|
|
void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AttrList) {
|
2008-06-29 08:43:07 +08:00
|
|
|
while (AttrList) {
|
2009-06-18 05:51:59 +08:00
|
|
|
ProcessDeclAttribute(S, D, *AttrList, *this);
|
2008-06-29 08:43:07 +08:00
|
|
|
AttrList = AttrList->getNext();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-30 11:15:39 +08:00
|
|
|
/// DeclClonePragmaWeak - clone existing decl (maybe definition),
|
|
|
|
/// #pragma weak needs a non-definition decl and source may not have one
|
2009-07-31 10:52:19 +08:00
|
|
|
NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II)
|
2009-07-30 11:15:39 +08:00
|
|
|
{
|
2009-07-31 10:52:19 +08:00
|
|
|
assert(isa<FunctionDecl>(ND) || isa<VarDecl>(ND));
|
2009-07-30 11:15:39 +08:00
|
|
|
NamedDecl *NewD = 0;
|
|
|
|
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
|
|
|
|
NewD = FunctionDecl::Create(FD->getASTContext(), FD->getDeclContext(),
|
|
|
|
FD->getLocation(), DeclarationName(II),
|
2009-08-19 09:27:57 +08:00
|
|
|
FD->getType(), FD->getDeclaratorInfo());
|
2009-07-30 11:15:39 +08:00
|
|
|
} else if (VarDecl *VD = dyn_cast<VarDecl>(ND)) {
|
|
|
|
NewD = VarDecl::Create(VD->getASTContext(), VD->getDeclContext(),
|
|
|
|
VD->getLocation(), II,
|
2009-08-19 09:27:57 +08:00
|
|
|
VD->getType(), VD->getDeclaratorInfo(),
|
|
|
|
VD->getStorageClass());
|
2009-07-30 11:15:39 +08:00
|
|
|
}
|
|
|
|
return NewD;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// DeclApplyPragmaWeak - A declaration (maybe definition) needs #pragma weak
|
|
|
|
/// applied to it, possibly with an alias.
|
2009-07-31 10:52:19 +08:00
|
|
|
void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) {
|
2009-07-30 11:15:39 +08:00
|
|
|
if (!W.getUsed()) { // only do this once
|
|
|
|
W.setUsed(true);
|
|
|
|
if (W.getAlias()) { // clone decl, impersonate __attribute(weak,alias(...))
|
|
|
|
IdentifierInfo *NDId = ND->getIdentifier();
|
|
|
|
NamedDecl *NewD = DeclClonePragmaWeak(ND, W.getAlias());
|
|
|
|
NewD->addAttr(::new (Context) AliasAttr(NDId->getName()));
|
|
|
|
NewD->addAttr(::new (Context) WeakAttr());
|
2009-07-31 10:52:19 +08:00
|
|
|
WeakTopLevelDecl.push_back(NewD);
|
|
|
|
// FIXME: "hideous" code from Sema::LazilyCreateBuiltin
|
|
|
|
// to insert Decl at TU scope, sorry.
|
|
|
|
DeclContext *SavedContext = CurContext;
|
|
|
|
CurContext = Context.getTranslationUnitDecl();
|
|
|
|
PushOnScopeChains(NewD, S);
|
|
|
|
CurContext = SavedContext;
|
2009-07-30 11:15:39 +08:00
|
|
|
} else { // just add weak to existing
|
|
|
|
ND->addAttr(::new (Context) WeakAttr());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-29 08:23:49 +08:00
|
|
|
/// ProcessDeclAttributes - Given a declarator (PD) with attributes indicated in
|
|
|
|
/// it, apply them to D. This is a bit tricky because PD can have attributes
|
|
|
|
/// specified in many different places, and we need to find and apply them all.
|
2009-06-18 05:51:59 +08:00
|
|
|
void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) {
|
2009-07-30 11:15:39 +08:00
|
|
|
// Handle #pragma weak
|
|
|
|
if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
|
|
|
|
if (ND->hasLinkage()) {
|
|
|
|
WeakInfo W = WeakUndeclaredIdentifiers.lookup(ND->getIdentifier());
|
|
|
|
if (W != WeakInfo()) {
|
2009-07-31 10:52:19 +08:00
|
|
|
// Identifier referenced by #pragma weak before it was declared
|
|
|
|
DeclApplyPragmaWeak(S, ND, W);
|
2009-07-30 11:15:39 +08:00
|
|
|
WeakUndeclaredIdentifiers[ND->getIdentifier()] = W;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-29 08:23:49 +08:00
|
|
|
// Apply decl attributes from the DeclSpec if present.
|
|
|
|
if (const AttributeList *Attrs = PD.getDeclSpec().getAttributes())
|
2009-06-18 05:51:59 +08:00
|
|
|
ProcessDeclAttributeList(S, D, Attrs);
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-06-29 08:23:49 +08:00
|
|
|
// Walk the declarator structure, applying decl attributes that were in a type
|
|
|
|
// position to the decl itself. This handles cases like:
|
|
|
|
// int *__attr__(x)** D;
|
|
|
|
// when X is a decl attribute.
|
|
|
|
for (unsigned i = 0, e = PD.getNumTypeObjects(); i != e; ++i)
|
|
|
|
if (const AttributeList *Attrs = PD.getTypeObject(i).getAttrs())
|
2009-06-18 05:51:59 +08:00
|
|
|
ProcessDeclAttributeList(S, D, Attrs);
|
2009-07-25 03:02:52 +08:00
|
|
|
|
2008-06-29 08:23:49 +08:00
|
|
|
// Finally, apply any attributes on the decl itself.
|
|
|
|
if (const AttributeList *Attrs = PD.getAttributes())
|
2009-06-18 05:51:59 +08:00
|
|
|
ProcessDeclAttributeList(S, D, Attrs);
|
2008-06-29 08:23:49 +08:00
|
|
|
}
|