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"
|
2008-07-23 00:56:21 +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
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2008-10-19 10:04:16 +08:00
|
|
|
static const FunctionType *getFunctionType(Decl *d) {
|
2008-06-27 02:38:35 +08:00
|
|
|
QualType Ty;
|
|
|
|
if (ValueDecl *decl = dyn_cast<ValueDecl>(d))
|
|
|
|
Ty = decl->getType();
|
|
|
|
else if (FieldDecl *decl = dyn_cast<FieldDecl>(d))
|
|
|
|
Ty = decl->getType();
|
|
|
|
else if (TypedefDecl* decl = dyn_cast<TypedefDecl>(d))
|
|
|
|
Ty = decl->getUnderlyingType();
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (Ty->isFunctionPointerType())
|
|
|
|
Ty = Ty->getAsPointerType()->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.
|
|
|
|
|
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.
|
2008-09-26 12:12:28 +08:00
|
|
|
static bool isFunctionOrMethod(Decl *d) {
|
2008-10-19 10:04:16 +08:00
|
|
|
return getFunctionType(d) || isa<ObjCMethodDecl>(d);
|
|
|
|
}
|
2008-09-26 12:12:28 +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
|
|
|
|
/// isFunctionOrMethod.
|
|
|
|
static bool hasFunctionProto(Decl *d) {
|
|
|
|
if (const FunctionType *FnTy = getFunctionType(d)) {
|
2009-02-27 07:50:07 +08:00
|
|
|
return isa<FunctionProtoType>(FnTy);
|
2008-10-19 10:04:16 +08:00
|
|
|
} else {
|
|
|
|
assert(isa<ObjCMethodDecl>(d));
|
|
|
|
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).
|
2008-09-26 12:12:28 +08:00
|
|
|
static unsigned getFunctionOrMethodNumArgs(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-02-21 02:43:26 +08:00
|
|
|
return cast<ObjCMethodDecl>(d)->param_size();
|
2008-09-26 12:12:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static QualType getFunctionOrMethodArgType(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-02-21 02:43:26 +08:00
|
|
|
|
|
|
|
return cast<ObjCMethodDecl>(d)->param_begin()[Idx]->getType();
|
2008-09-26 12:12:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool isFunctionOrMethodVariadic(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();
|
|
|
|
} else {
|
|
|
|
return cast<ObjCMethodDecl>(d)->isVariadic();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-27 02:38:35 +08:00
|
|
|
static inline bool isNSStringType(QualType T, ASTContext &Ctx) {
|
2008-07-27 06:17:49 +08:00
|
|
|
const PointerType *PT = T->getAsPointerType();
|
|
|
|
if (!PT)
|
2008-06-27 02:38:35 +08:00
|
|
|
return false;
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
IdentifierInfo* ClsName = ClsT->getDecl()->getIdentifier();
|
|
|
|
|
|
|
|
// 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) {
|
|
|
|
const PointerType *PT = T->getAsPointerType();
|
|
|
|
if (!PT)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const RecordType *RT = PT->getPointeeType()->getAsRecordType();
|
|
|
|
if (!RT)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
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).
|
|
|
|
|
2008-06-29 08:43:07 +08:00
|
|
|
static void HandleExtVectorTypeAttr(Decl *d, 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
|
|
|
}
|
|
|
|
|
|
|
|
QualType curType = tDecl->getUnderlyingType();
|
|
|
|
// 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;
|
|
|
|
}
|
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)
|
|
|
|
<< "ext_vector_type" << sizeExpr->getSourceRange();
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
// unlike gcc's vector_size attribute, we do not allow vectors to be defined
|
|
|
|
// in conjunction with complex types (pointers, arrays, functions, etc.).
|
2008-07-27 06:17:49 +08:00
|
|
|
if (!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-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
// unlike gcc's vector_size attribute, the size is specified as the
|
|
|
|
// number of elements, not the number of bytes.
|
|
|
|
unsigned vectorSize = static_cast<unsigned>(vecSize.getZExtValue());
|
|
|
|
|
|
|
|
if (vectorSize == 0) {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_zero_size)
|
|
|
|
<< sizeExpr->getSourceRange();
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Instantiate/Install the vector type, the number of elements is > 0.
|
2008-06-29 08:43:07 +08:00
|
|
|
tDecl->setUnderlyingType(S.Context.getExtVectorType(curType, vectorSize));
|
2008-06-27 02:38:35 +08:00
|
|
|
// Remember this typedef decl, we will need it later for diagnostics.
|
2008-06-29 08:43:07 +08:00
|
|
|
S.ExtVectorDecls.push_back(tDecl);
|
2008-06-27 02:38:35 +08:00
|
|
|
}
|
|
|
|
|
2008-06-29 07:48:25 +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;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
}
|
|
|
|
// 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()) {
|
2008-06-27 02:38:35 +08:00
|
|
|
assert(0 && "HandleVector(): Complex type construction unimplemented");
|
|
|
|
/* 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());
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
// the base type must be integer or float.
|
2008-07-27 06:17:49 +08:00
|
|
|
if (!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.
|
|
|
|
unsigned vectorSize = static_cast<unsigned>(vecSize.getZExtValue() * 8);
|
|
|
|
|
|
|
|
// 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
|
|
|
}
|
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);
|
2008-06-29 07:48:25 +08:00
|
|
|
|
|
|
|
if (ValueDecl *VD = dyn_cast<ValueDecl>(D))
|
|
|
|
VD->setType(CurType);
|
|
|
|
else
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (TagDecl *TD = dyn_cast<TagDecl>(d))
|
2008-10-16 10:34:03 +08:00
|
|
|
TD->addAttr(new PackedAttr(1));
|
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
|
2008-10-16 10:34:03 +08:00
|
|
|
FD->addAttr(new PackedAttr(1));
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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))
|
|
|
|
d->addAttr(new 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) {
|
|
|
|
// 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-02-14 15:37:35 +08:00
|
|
|
<< "nonnull" << 0 /*function*/;
|
2008-07-22 05:53:04 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
for (AttributeList::arg_iterator I=Attr.arg_begin(),
|
|
|
|
E=Attr.arg_end(); I!=E; ++I) {
|
|
|
|
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned x = (unsigned) ArgNum.getZExtValue();
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2008-07-22 06:09:15 +08:00
|
|
|
|
|
|
|
--x;
|
2008-07-22 05:53:04 +08:00
|
|
|
|
|
|
|
// Is the function argument a pointer type?
|
2008-11-18 14:52:58 +08:00
|
|
|
QualType T = getFunctionOrMethodArgType(d, x);
|
|
|
|
if (!T->isPointerType() && !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
|
|
|
}
|
|
|
|
|
|
|
|
NonNullArgs.push_back(x);
|
|
|
|
}
|
|
|
|
|
2008-09-02 03:57:52 +08:00
|
|
|
// If no arguments were specified to __attribute__((nonnull)) then all
|
|
|
|
// pointer arguments have a nonnull attribute.
|
|
|
|
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);
|
|
|
|
if (T->isPointerType() || T->isBlockPointerType())
|
2008-10-19 10:04:16 +08:00
|
|
|
NonNullArgs.push_back(I);
|
2008-11-18 14:52:58 +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);
|
|
|
|
d->addAttr(new 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;
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *Alias = Str->getStrData();
|
|
|
|
unsigned AliasLen = Str->getByteLength();
|
|
|
|
|
|
|
|
// FIXME: check if target symbol exists in current file
|
|
|
|
|
|
|
|
d->addAttr(new AliasAttr(std::string(Alias, AliasLen)));
|
|
|
|
}
|
|
|
|
|
2008-10-28 08:17:57 +08:00
|
|
|
static void HandleAlwaysInlineAttr(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-28 08:17:57 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-02-20 03:16:48 +08:00
|
|
|
|
|
|
|
if (!isFunctionOrMethod(d)) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
|
|
|
<< "always_inline" << 0 /*function*/;
|
|
|
|
return;
|
|
|
|
}
|
2008-10-28 08:17:57 +08:00
|
|
|
|
|
|
|
d->addAttr(new AlwaysInlineAttr());
|
|
|
|
}
|
|
|
|
|
2008-06-29 08:43:07 +08:00
|
|
|
static void HandleNoReturnAttr(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-10-19 10:04:16 +08:00
|
|
|
|
|
|
|
if (!isFunctionOrMethod(d)) {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
2009-02-14 15:37:35 +08:00
|
|
|
<< "noreturn" << 0 /*function*/;
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
d->addAttr(new NoReturnAttr());
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
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-02-14 15:37:35 +08:00
|
|
|
<< "unused" << 2 /*variable and function*/;
|
2008-07-25 12:39:19 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
d->addAttr(new UnusedAttr());
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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-02-14 15:37:35 +08:00
|
|
|
<< "used" << 2 /*variable and function*/;
|
2009-02-14 03:23:53 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
d->addAttr(new UsedAttr());
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
|
|
|
FunctionDecl *Fn = dyn_cast<FunctionDecl>(d);
|
|
|
|
if (!Fn) {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
2009-02-14 15:37:35 +08:00
|
|
|
<< "constructor" << 0 /*function*/;
|
2008-08-01 06:40:48 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
d->addAttr(new ConstructorAttr(priority));
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
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-02-14 15:37:35 +08:00
|
|
|
<< "destructor" << 0 /*function*/;
|
2008-08-01 06:40:48 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
d->addAttr(new DestructorAttr(priority));
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
d->addAttr(new DeprecatedAttr());
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
d->addAttr(new UnavailableAttr());
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *TypeStr = Str->getStrData();
|
|
|
|
unsigned TypeLen = Str->getByteLength();
|
|
|
|
VisibilityAttr::VisibilityTypes type;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
d->addAttr(new VisibilityAttr(type));
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
ObjCInterfaceDecl *OCI = dyn_cast<ObjCInterfaceDecl>(D);
|
|
|
|
if (OCI == 0) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_requires_objc_interface);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
D->addAttr(new ObjCExceptionAttr());
|
|
|
|
}
|
|
|
|
|
|
|
|
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() ||
|
|
|
|
!T->getAsPointerType()->getPointeeType()->isRecordType()) {
|
|
|
|
S.Diag(TD->getLocation(), diag::err_nsobject_attribute);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2009-02-14 16:09:34 +08:00
|
|
|
D->addAttr(new ObjCNSObjectAttr);
|
2009-01-14 07:34:40 +08:00
|
|
|
}
|
|
|
|
|
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
|
|
|
static void
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
D->addAttr(new OverloadableAttr);
|
|
|
|
}
|
|
|
|
|
2008-09-19 00:44:58 +08:00
|
|
|
static void HandleBlocksAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
d->addAttr(new BlocksAttr(type));
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
|
|
|
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)) {
|
|
|
|
QualType FT = FD->getType();
|
2009-02-27 07:50:07 +08:00
|
|
|
if (!FT->getAsFunctionProtoType()->isVariadic()) {
|
2008-10-06 02:05:59 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(d)) {
|
|
|
|
if (!MD->isVariadic()) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
2009-02-14 15:37:35 +08:00
|
|
|
<< "sentinel" << 3 /*function or method*/;
|
2008-10-06 02:05:59 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: Actually create the attribute.
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
<< "warn_unused_result" << 0 /*function*/;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Fn->addAttr(new WarnUnusedResultAttr());
|
|
|
|
}
|
|
|
|
|
|
|
|
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-02-14 15:37:35 +08:00
|
|
|
D->addAttr(new WeakAttr());
|
2008-06-27 02:38:35 +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)) {
|
|
|
|
D->addAttr(new 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-02-14 15:37:35 +08:00
|
|
|
<< "dllimport" << 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-02-14 15:37:35 +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-02-14 15:37:35 +08:00
|
|
|
D->addAttr(new 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)) {
|
|
|
|
D->addAttr(new 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-02-14 15:37:35 +08:00
|
|
|
<< "dllexport" << 2 /*variable and function*/;
|
2008-12-26 08:52:02 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Currently, the dllexport attribute is ignored for inlined functions,
|
|
|
|
// unless the -fkeep-inline-functions flag has been used. Warning is emitted;
|
|
|
|
if (FD->isInline()) {
|
|
|
|
// FIXME: ... unless the -fkeep-inline-functions flag has been used.
|
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllexport";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-02-14 15:37:35 +08:00
|
|
|
D->addAttr(new DLLExportAttr());
|
2008-06-27 02:38:35 +08:00
|
|
|
}
|
|
|
|
|
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.
|
|
|
|
StringLiteral *SE =
|
|
|
|
dyn_cast<StringLiteral>(static_cast<Expr *>(Attr.getArg(0)));
|
|
|
|
if (!SE) {
|
|
|
|
// FIXME
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_annotate_no_string);
|
|
|
|
return;
|
|
|
|
}
|
2009-02-14 15:37:35 +08:00
|
|
|
D->addAttr(new SectionAttr(std::string(SE->getStrData(),
|
2009-02-13 01:28:23 +08:00
|
|
|
SE->getByteLength())));
|
|
|
|
}
|
|
|
|
|
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-02-14 15:37:35 +08:00
|
|
|
<< "stdcall" << 0 /*function*/;
|
2008-12-24 06:24:07 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// stdcall and fastcall attributes are mutually incompatible.
|
|
|
|
if (d->getAttr<FastCallAttr>()) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
|
|
|
|
<< "stdcall" << "fastcall";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-06-27 02:38:35 +08:00
|
|
|
d->addAttr(new StdCallAttr());
|
|
|
|
}
|
|
|
|
|
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-02-14 15:37:35 +08:00
|
|
|
<< "fastcall" << 0 /*function*/;
|
2008-12-24 06:24:07 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// stdcall and fastcall attributes are mutually incompatible.
|
|
|
|
if (d->getAttr<StdCallAttr>()) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
|
|
|
|
<< "fastcall" << "stdcall";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-06-27 02:38:35 +08:00
|
|
|
d->addAttr(new FastCallAttr());
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
d->addAttr(new NoThrowAttr());
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
d->addAttr(new ConstAttr());
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
d->addAttr(new PureAttr());
|
|
|
|
}
|
|
|
|
|
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-01-31 09:16:18 +08:00
|
|
|
if (!Attr.getParameterName()) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Attr.getNumArgs() != 0) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
VarDecl *VD = dyn_cast<VarDecl>(d);
|
|
|
|
|
|
|
|
if (!VD || !VD->hasLocalStorage()) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "cleanup";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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-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-02-26 01:19:08 +08:00
|
|
|
if (S.CheckAssignmentConstraints(Ty, ParamTy) != Sema::Compatible) {
|
2009-02-08 07:16:50 +08:00
|
|
|
S.Diag(Attr.getLoc(),
|
|
|
|
diag::err_attribute_cleanup_func_arg_incompatible_type) <<
|
|
|
|
Attr.getParameterName() << ParamTy << Ty;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-01-31 09:16:18 +08:00
|
|
|
d->addAttr(new CleanupAttr(FD));
|
|
|
|
}
|
|
|
|
|
2008-06-27 02:38:35 +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;
|
|
|
|
}
|
|
|
|
|
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-02-14 15:37:35 +08:00
|
|
|
<< "format" << 0 /*function*/;
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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;
|
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;
|
|
|
|
case 7: Supported = !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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
// 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) {
|
2008-06-27 02:38:35 +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)) {
|
2008-06-27 02:38:35 +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;
|
|
|
|
}
|
|
|
|
} else if (!Ty->isPointerType() ||
|
|
|
|
!Ty->getAsPointerType()->getPointeeType()->isCharType()) {
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
d->addAttr(new FormatAttr(std::string(Format, FormatLen),
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2008-09-02 13:19:23 +08:00
|
|
|
// FIXME: This shouldn't be restricted to typedefs
|
|
|
|
TypedefDecl *TD = dyn_cast<TypedefDecl>(d);
|
|
|
|
if (!TD || !TD->getUnderlyingType()->isUnionType()) {
|
2008-11-19 13:08:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
2009-02-14 15:37:35 +08:00
|
|
|
<< "transparent_union" << 1 /*union*/;
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-09-02 13:19:23 +08:00
|
|
|
RecordDecl* RD = TD->getUnderlyingType()->getAsUnionType()->getDecl();
|
|
|
|
|
|
|
|
// FIXME: Should we do a check for RD->isDefinition()?
|
|
|
|
|
|
|
|
// FIXME: This isn't supposed to be restricted to pointers, but otherwise
|
|
|
|
// we might silently generate incorrect code; see following code
|
2008-12-12 00:49:14 +08:00
|
|
|
for (RecordDecl::field_iterator Field = RD->field_begin(),
|
|
|
|
FieldEnd = RD->field_end();
|
|
|
|
Field != FieldEnd; ++Field) {
|
|
|
|
if (!Field->getType()->isPointerType()) {
|
2008-09-02 13:19:23 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::warn_transparent_union_nonpointer);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2008-06-27 02:38:35 +08:00
|
|
|
|
2008-09-02 13:19:23 +08:00
|
|
|
// FIXME: This is a complete hack; we should be properly propagating
|
|
|
|
// transparent_union through Sema. That said, this is close enough to
|
|
|
|
// correctly compile all the common cases of transparent_union without
|
|
|
|
// errors or warnings
|
|
|
|
QualType NewTy = S.Context.VoidPtrTy;
|
|
|
|
NewTy.addConst();
|
|
|
|
TD->setUnderlyingType(NewTy);
|
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;
|
|
|
|
}
|
2008-06-29 07:36:30 +08:00
|
|
|
Expr *argExpr = static_cast<Expr *>(Attr.getArg(0));
|
2008-06-27 02:38:35 +08:00
|
|
|
StringLiteral *SE = dyn_cast<StringLiteral>(argExpr);
|
|
|
|
|
|
|
|
// Make sure that there is a string literal as the annotation's single
|
|
|
|
// argument.
|
|
|
|
if (!SE) {
|
2008-06-29 08:28:59 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_annotate_no_string);
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
d->addAttr(new AnnotateAttr(std::string(SE->getStrData(),
|
|
|
|
SE->getByteLength())));
|
|
|
|
}
|
|
|
|
|
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-02-19 04:06:09 +08:00
|
|
|
d->addAttr(new AlignedAttr(Align));
|
2008-06-27 02:38:35 +08:00
|
|
|
return;
|
|
|
|
}
|
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())) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_aligned_not_power_of_two)
|
|
|
|
<< alignmentExpr->getSourceRange();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-06-29 07:50:44 +08:00
|
|
|
d->addAttr(new AlignedAttr(Alignment.getZExtValue() * 8));
|
2008-06-27 02:38:35 +08:00
|
|
|
}
|
2008-06-28 06:18:37 +08:00
|
|
|
|
2008-06-29 08:28:59 +08:00
|
|
|
/// HandleModeAttr - This attribute modifies the width of a decl with
|
2008-06-29 07:48:25 +08:00
|
|
|
/// primitive type.
|
2008-06-28 06:18:37 +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;
|
|
|
|
switch (Len) {
|
|
|
|
case 2:
|
|
|
|
if (!memcmp(Str, "QI", 2)) { DestWidth = 8; break; }
|
|
|
|
if (!memcmp(Str, "HI", 2)) { DestWidth = 16; break; }
|
|
|
|
if (!memcmp(Str, "SI", 2)) { DestWidth = 32; break; }
|
|
|
|
if (!memcmp(Str, "DI", 2)) { DestWidth = 64; break; }
|
|
|
|
if (!memcmp(Str, "TI", 2)) { DestWidth = 128; break; }
|
|
|
|
if (!memcmp(Str, "SF", 2)) { DestWidth = 32; IntegerMode = false; break; }
|
|
|
|
if (!memcmp(Str, "DF", 2)) { DestWidth = 64; IntegerMode = false; break; }
|
|
|
|
if (!memcmp(Str, "XF", 2)) { DestWidth = 96; IntegerMode = false; break; }
|
|
|
|
if (!memcmp(Str, "TF", 2)) { DestWidth = 128; IntegerMode = false; break; }
|
|
|
|
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-02-13 10:31:07 +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.
|
|
|
|
// 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:
|
|
|
|
assert(IntegerMode);
|
|
|
|
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:
|
|
|
|
assert(IntegerMode);
|
|
|
|
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-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());
|
2008-06-28 06:18:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!OldTy->getAsBuiltinType())
|
2008-06-29 08:28:59 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_mode_not_primitive);
|
2008-06-28 06:18:37 +08:00
|
|
|
else if (!(IntegerMode && OldTy->isIntegerType()) &&
|
|
|
|
!(!IntegerMode && OldTy->isFloatingType())) {
|
2008-06-29 08:28:59 +08:00
|
|
|
S.Diag(Attr.getLoc(), diag::err_mode_wrong_type);
|
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-02-14 15:37:35 +08:00
|
|
|
<< "nodebug" << 0 /*function*/;
|
2009-02-13 14:46:13 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
d->addAttr(new NodebugAttr());
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isFunctionOrMethod(d)) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
|
|
|
<< "noinline" << 0 /*function*/;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
d->addAttr(new NoinlineAttr());
|
|
|
|
}
|
|
|
|
|
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.
|
|
|
|
static void ProcessDeclAttribute(Decl *D, const AttributeList &Attr, Sema &S) {
|
|
|
|
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:
|
|
|
|
// 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;
|
2008-10-28 08:17:57 +08:00
|
|
|
case AttributeList::AT_always_inline:
|
|
|
|
HandleAlwaysInlineAttr (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:
|
|
|
|
HandleExtVectorTypeAttr(D, Attr, S);
|
|
|
|
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;
|
2008-08-01 06:40:48 +08:00
|
|
|
case AttributeList::AT_mode: HandleModeAttr (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;
|
|
|
|
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;
|
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-02-13 16:16:43 +08:00
|
|
|
case AttributeList::IgnoredAttribute:
|
|
|
|
// 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.
|
|
|
|
void Sema::ProcessDeclAttributeList(Decl *D, const AttributeList *AttrList) {
|
|
|
|
while (AttrList) {
|
|
|
|
ProcessDeclAttribute(D, *AttrList, *this);
|
|
|
|
AttrList = AttrList->getNext();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
void Sema::ProcessDeclAttributes(Decl *D, const Declarator &PD) {
|
|
|
|
// Apply decl attributes from the DeclSpec if present.
|
|
|
|
if (const AttributeList *Attrs = PD.getDeclSpec().getAttributes())
|
|
|
|
ProcessDeclAttributeList(D, Attrs);
|
2008-06-29 08:43:07 +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())
|
|
|
|
ProcessDeclAttributeList(D, Attrs);
|
|
|
|
|
|
|
|
// Finally, apply any attributes on the decl itself.
|
|
|
|
if (const AttributeList *Attrs = PD.getAttributes())
|
|
|
|
ProcessDeclAttributeList(D, Attrs);
|
|
|
|
}
|
|
|
|
|