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))
|
2009-03-04 14:34:08 +08:00
|
|
|
TD->addAttr(::new (S.Context) 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
|
2009-03-04 14:34:08 +08:00
|
|
|
FD->addAttr(::new (S.Context) 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))
|
2009-03-04 14:34:08 +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) {
|
|
|
|
// 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);
|
2009-03-04 14:34:08 +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;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
|
2009-03-04 14:34:08 +08:00
|
|
|
d->addAttr(::new (S.Context) AliasAttr(std::string(Alias, AliasLen)));
|
2008-06-27 02:38:35 +08:00
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2009-03-04 14:34:08 +08:00
|
|
|
d->addAttr(::new (S.Context) AlwaysInlineAttr());
|
2008-10-28 08:17:57 +08:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-03-04 14:34:08 +08:00
|
|
|
d->addAttr(::new (S.Context) NoReturnAttr());
|
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;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-03-04 14:34:08 +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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-03-04 14:34:08 +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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-03-04 14:34:08 +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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-03-04 14:34:08 +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-03-04 14:34:08 +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-03-04 14:34:08 +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;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-03-04 14:34:08 +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;
|
|
|
|
}
|
|
|
|
|
|
|
|
ObjCInterfaceDecl *OCI = dyn_cast<ObjCInterfaceDecl>(D);
|
|
|
|
if (OCI == 0) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::err_attribute_requires_objc_interface);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-03-04 14:34:08 +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() ||
|
|
|
|
!T->getAsPointerType()->getPointeeType()->isRecordType()) {
|
|
|
|
S.Diag(TD->getLocation(), diag::err_nsobject_attribute);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2009-03-04 14:34:08 +08:00
|
|
|
D->addAttr(::new (S.Context) 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;
|
|
|
|
}
|
|
|
|
|
2009-03-04 14:34:08 +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) {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-03-04 14:34:08 +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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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)) {
|
2009-03-18 07:03:47 +08:00
|
|
|
const FunctionType *FT = FD->getType()->getAsFunctionType();
|
|
|
|
assert(FT && "FunctionDecl has non-function type?");
|
|
|
|
|
|
|
|
if (isa<FunctionNoProtoType>(FT)) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_named_arguments);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!cast<FunctionProtoType>(FT)->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;
|
|
|
|
}
|
|
|
|
|
2009-03-04 14:34:08 +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
|
|
|
|
|
|
|
// TODO: could also be applied to methods?
|
|
|
|
if (!isa<FunctionDecl>(D) && !isa<VarDecl>(D)) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
|
|
|
<< "weak" << 2 /*variable and function*/;
|
|
|
|
return;
|
|
|
|
}
|
2008-06-27 02:38:35 +08:00
|
|
|
|
2009-03-04 14:34:08 +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;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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)) {
|
|
|
|
isDef = FD->getBody();
|
2009-03-18 23:05:17 +08:00
|
|
|
} else if (isa<ObjCPropertyDecl>(D)) {
|
|
|
|
// We ignore weak import on properties
|
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)
|
|
|
|
<< "weak_import" << 2 /*variable and function*/;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Merge should handle any subsequent violations.
|
|
|
|
if (isDef) {
|
|
|
|
S.Diag(Attr.getLoc(),
|
|
|
|
diag::warn_attribute_weak_import_invalid_on_definition)
|
|
|
|
<< "weak_import" << 2 /*variable and function*/;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
D->addAttr(::new (S.Context) WeakImportAttr());
|
|
|
|
}
|
|
|
|
|
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-03-04 14:34:08 +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-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-03-04 14:34:08 +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-03-04 14:34:08 +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-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-03-04 14:34:08 +08:00
|
|
|
D->addAttr(::new (S.Context) 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-03-04 14:34:08 +08:00
|
|
|
D->addAttr(::new (S.Context) SectionAttr(std::string(SE->getStrData(),
|
|
|
|
SE->getByteLength())));
|
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-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;
|
|
|
|
}
|
|
|
|
|
2009-03-04 14:34:08 +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-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;
|
|
|
|
}
|
|
|
|
|
2009-03-04 14:34:08 +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-03-04 14:34:08 +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-03-04 14:34:08 +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-03-04 14:34:08 +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-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-03-04 14:34:08 +08:00
|
|
|
d->addAttr(::new (S.Context) CleanupAttr(FD));
|
2009-01-31 09:16:18 +08:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-03-04 14:34:08 +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;
|
|
|
|
}
|
|
|
|
|
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
|
2009-04-10 05:40:53 +08:00
|
|
|
for (RecordDecl::field_iterator Field = RD->field_begin(S.Context),
|
|
|
|
FieldEnd = RD->field_end(S.Context);
|
2008-12-12 00:49:14 +08:00
|
|
|
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;
|
|
|
|
}
|
2009-03-04 14:34:08 +08:00
|
|
|
d->addAttr(::new (S.Context) AnnotateAttr(std::string(SE->getStrData(),
|
|
|
|
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-03-04 14:34:08 +08:00
|
|
|
d->addAttr(::new (S.Context) 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;
|
|
|
|
}
|
|
|
|
|
2009-03-04 14:34:08 +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
|
|
|
|
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;
|
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-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:
|
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-02-14 15:37:35 +08:00
|
|
|
<< "nodebug" << 0 /*function*/;
|
2009-02-13 14:46:13 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-03-04 14:34:08 +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;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isFunctionOrMethod(d)) {
|
|
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
|
|
|
<< "noinline" << 0 /*function*/;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-03-04 14:34:08 +08:00
|
|
|
d->addAttr(::new (S.Context) NoinlineAttr());
|
2009-02-20 03:16:48 +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)
|
|
|
|
<< "regparm" << 0 /*function*/;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
d->addAttr(::new (S.Context) RegparmAttr(NumParams.getZExtValue()));
|
2009-03-28 02:38:55 +08:00
|
|
|
}
|
|
|
|
|
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;
|
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-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);
|
|
|
|
}
|
|
|
|
|