summaryrefslogtreecommitdiff
path: root/lib/Sema/SemaDeclAttr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaDeclAttr.cpp')
-rw-r--r--lib/Sema/SemaDeclAttr.cpp544
1 files changed, 330 insertions, 214 deletions
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 2b71df722459..50ebb49e7d5b 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -17,46 +17,53 @@
#include "clang/AST/Expr.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Parse/DeclSpec.h"
-#include <llvm/ADT/StringExtras.h>
+#include "llvm/ADT/StringExtras.h"
using namespace clang;
//===----------------------------------------------------------------------===//
// Helper functions
//===----------------------------------------------------------------------===//
-static const FunctionType *getFunctionType(Decl *d, bool blocksToo = true) {
+static const FunctionType *getFunctionType(const Decl *d,
+ bool blocksToo = true) {
QualType Ty;
- if (ValueDecl *decl = dyn_cast<ValueDecl>(d))
+ if (const ValueDecl *decl = dyn_cast<ValueDecl>(d))
Ty = decl->getType();
- else if (FieldDecl *decl = dyn_cast<FieldDecl>(d))
+ else if (const FieldDecl *decl = dyn_cast<FieldDecl>(d))
Ty = decl->getType();
- else if (TypedefDecl* decl = dyn_cast<TypedefDecl>(d))
+ else if (const TypedefDecl* decl = dyn_cast<TypedefDecl>(d))
Ty = decl->getUnderlyingType();
else
return 0;
-
+
if (Ty->isFunctionPointerType())
- Ty = Ty->getAsPointerType()->getPointeeType();
+ Ty = Ty->getAs<PointerType>()->getPointeeType();
else if (blocksToo && Ty->isBlockPointerType())
- Ty = Ty->getAsBlockPointerType()->getPointeeType();
+ Ty = Ty->getAs<BlockPointerType>()->getPointeeType();
- return Ty->getAsFunctionType();
+ return Ty->getAs<FunctionType>();
}
// FIXME: We should provide an abstraction around a method or function
// to provide the following bits of information.
/// isFunctionOrMethod - Return true if the given decl has function
+/// type (function or function-typed variable).
+static bool isFunction(const Decl *d) {
+ return getFunctionType(d, false) != NULL;
+}
+
+/// isFunctionOrMethod - Return true if the given decl has function
/// type (function or function-typed variable) or an Objective-C
/// method.
-static bool isFunctionOrMethod(Decl *d) {
- return getFunctionType(d, false) || isa<ObjCMethodDecl>(d);
+static bool isFunctionOrMethod(const Decl *d) {
+ return isFunction(d)|| isa<ObjCMethodDecl>(d);
}
/// isFunctionOrMethodOrBlock - Return true if the given decl has function
/// type (function or function-typed variable) or an Objective-C
/// method or a block.
-static bool isFunctionOrMethodOrBlock(Decl *d) {
+static bool isFunctionOrMethodOrBlock(const Decl *d) {
if (isFunctionOrMethod(d))
return true;
// check for block is more involved.
@@ -70,7 +77,7 @@ static bool isFunctionOrMethodOrBlock(Decl *d) {
/// hasFunctionProto - Return true if the given decl has a argument
/// information. This decl should have already passed
/// isFunctionOrMethod or isFunctionOrMethodOrBlock.
-static bool hasFunctionProto(Decl *d) {
+static bool hasFunctionProto(const Decl *d) {
if (const FunctionType *FnTy = getFunctionType(d))
return isa<FunctionProtoType>(FnTy);
else {
@@ -82,7 +89,7 @@ static bool hasFunctionProto(Decl *d) {
/// getFunctionOrMethodNumArgs - Return number of function or method
/// arguments. It is an error to call this on a K&R function (use
/// hasFunctionProto first).
-static unsigned getFunctionOrMethodNumArgs(Decl *d) {
+static unsigned getFunctionOrMethodNumArgs(const Decl *d) {
if (const FunctionType *FnTy = getFunctionType(d))
return cast<FunctionProtoType>(FnTy)->getNumArgs();
if (const BlockDecl *BD = dyn_cast<BlockDecl>(d))
@@ -90,22 +97,22 @@ static unsigned getFunctionOrMethodNumArgs(Decl *d) {
return cast<ObjCMethodDecl>(d)->param_size();
}
-static QualType getFunctionOrMethodArgType(Decl *d, unsigned Idx) {
+static QualType getFunctionOrMethodArgType(const Decl *d, unsigned Idx) {
if (const FunctionType *FnTy = getFunctionType(d))
return cast<FunctionProtoType>(FnTy)->getArgType(Idx);
if (const BlockDecl *BD = dyn_cast<BlockDecl>(d))
return BD->getParamDecl(Idx)->getType();
-
+
return cast<ObjCMethodDecl>(d)->param_begin()[Idx]->getType();
}
-static QualType getFunctionOrMethodResultType(Decl *d) {
+static QualType getFunctionOrMethodResultType(const Decl *d) {
if (const FunctionType *FnTy = getFunctionType(d))
return cast<FunctionProtoType>(FnTy)->getResultType();
return cast<ObjCMethodDecl>(d)->getResultType();
}
-static bool isFunctionOrMethodVariadic(Decl *d) {
+static bool isFunctionOrMethodVariadic(const Decl *d) {
if (const FunctionType *FnTy = getFunctionType(d)) {
const FunctionProtoType *proto = cast<FunctionProtoType>(FnTy);
return proto->isVariadic();
@@ -117,30 +124,30 @@ static bool isFunctionOrMethodVariadic(Decl *d) {
}
static inline bool isNSStringType(QualType T, ASTContext &Ctx) {
- const PointerType *PT = T->getAsPointerType();
+ const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>();
if (!PT)
return false;
-
- const ObjCInterfaceType *ClsT =PT->getPointeeType()->getAsObjCInterfaceType();
+
+ const ObjCInterfaceType *ClsT =PT->getPointeeType()->getAs<ObjCInterfaceType>();
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");
}
static inline bool isCFStringType(QualType T, ASTContext &Ctx) {
- const PointerType *PT = T->getAsPointerType();
+ const PointerType *PT = T->getAs<PointerType>();
if (!PT)
return false;
- const RecordType *RT = PT->getPointeeType()->getAsRecordType();
+ const RecordType *RT = PT->getPointeeType()->getAs<RecordType>();
if (!RT)
return false;
-
+
const RecordDecl *RD = RT->getDecl();
if (RD->getTagKind() != TagDecl::TK_struct)
return false;
@@ -156,14 +163,14 @@ static inline bool isCFStringType(QualType T, ASTContext &Ctx) {
// least add some helper functions to check most argument patterns (#
// and types of args).
-static void HandleExtVectorTypeAttr(Scope *scope, Decl *d,
+static void HandleExtVectorTypeAttr(Scope *scope, Decl *d,
const AttributeList &Attr, Sema &S) {
TypedefDecl *tDecl = dyn_cast<TypedefDecl>(d);
if (tDecl == 0) {
S.Diag(Attr.getLoc(), diag::err_typecheck_ext_vector_not_typedef);
return;
}
-
+
QualType curType = tDecl->getUnderlyingType();
Expr *sizeExpr;
@@ -187,21 +194,20 @@ static void HandleExtVectorTypeAttr(Scope *scope, Decl *d,
QualType T = S.BuildExtVectorType(curType, S.Owned(sizeExpr), Attr.getLoc());
if (!T.isNull()) {
tDecl->setUnderlyingType(T);
-
+
// Remember this typedef decl, we will need it later for diagnostics.
S.ExtVectorDecls.push_back(tDecl);
}
}
-/// 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.
+/// 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.
static void HandleVectorSizeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
QualType CurType;
if (ValueDecl *VD = dyn_cast<ValueDecl>(D))
@@ -213,7 +219,7 @@ static void HandleVectorSizeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
<< "vector_size" << SourceRange(Attr.getLoc(), Attr.getLoc());
return;
}
-
+
// Check the attribute arugments.
if (Attr.getNumArgs() != 1) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
@@ -226,8 +232,8 @@ static void HandleVectorSizeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
<< "vector_size" << sizeExpr->getSourceRange();
return;
}
- // navigate to the base type - we need to provide for vector pointers,
- // vector arrays, and functions returning vectors.
+ // navigate to the base type - we need to provide for vector pointers, vector
+ // arrays, and functions returning vectors.
if (CurType->isPointerType() || CurType->isArrayType() ||
CurType->isFunctionType()) {
S.Diag(Attr.getLoc(), diag::err_unsupported_vector_size) << CurType;
@@ -252,8 +258,8 @@ static void HandleVectorSizeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
}
unsigned typeSize = static_cast<unsigned>(S.Context.getTypeSize(CurType));
// vecSize is specified in bytes - convert to bits.
- unsigned vectorSize = static_cast<unsigned>(vecSize.getZExtValue() * 8);
-
+ unsigned vectorSize = static_cast<unsigned>(vecSize.getZExtValue() * 8);
+
// the vector size needs to be an integral multiple of the type size.
if (vectorSize % typeSize) {
S.Diag(Attr.getLoc(), diag::err_attribute_invalid_size)
@@ -265,14 +271,14 @@ static void HandleVectorSizeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
<< sizeExpr->getSourceRange();
return;
}
-
+
// Success! Instantiate the vector type, the number of elements is > 0, and
// not required to be a power of 2, unlike GCC.
CurType = S.Context.getVectorType(CurType, vectorSize/typeSize);
-
+
if (ValueDecl *VD = dyn_cast<ValueDecl>(D))
VD->setType(CurType);
- else
+ else
cast<TypedefDecl>(D)->setUnderlyingType(CurType);
}
@@ -282,9 +288,9 @@ static void HandlePackedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
-
+
if (TagDecl *TD = dyn_cast<TagDecl>(d))
- TD->addAttr(::new (S.Context) PackedAttr(1));
+ TD->addAttr(::new (S.Context) PackedAttr);
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.
@@ -293,7 +299,7 @@ static void HandlePackedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored_for_field_of_type)
<< Attr.getName() << FD->getType();
else
- FD->addAttr(::new (S.Context) PackedAttr(1));
+ FD->addAttr(::new (S.Context) PackedAttr);
} else
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
}
@@ -304,7 +310,7 @@ static void HandleIBOutletAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
-
+
// The IBOutlet attribute only applies to instance variables of Objective-C
// classes.
if (isa<ObjCIvarDecl>(d) || isa<ObjCPropertyDecl>(d))
@@ -314,23 +320,23 @@ static void HandleIBOutletAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
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
+ // GCC ignores the nonnull attribute on K&R style function prototypes, so we
+ // ignore it as well
if (!isFunctionOrMethod(d) || !hasFunctionProto(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << 0 /*function*/;
return;
}
-
+
unsigned NumArgs = getFunctionOrMethodNumArgs(d);
// 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.
Expr *Ex = static_cast<Expr *>(*I);
llvm::APSInt ArgNum(32);
@@ -339,38 +345,38 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) {
<< "nonnull" << Ex->getSourceRange();
return;
}
-
+
unsigned x = (unsigned) ArgNum.getZExtValue();
-
+
if (x < 1 || x > NumArgs) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
<< "nonnull" << I.getArgNum() << Ex->getSourceRange();
return;
}
-
+
--x;
// Is the function argument a pointer type?
- QualType T = getFunctionOrMethodArgType(d, x);
- if (!T->isPointerType() && !T->isBlockPointerType()) {
+ QualType T = getFunctionOrMethodArgType(d, x);
+ if (!T->isAnyPointerType() && !T->isBlockPointerType()) {
// FIXME: Should also highlight argument in decl.
S.Diag(Attr.getLoc(), diag::err_nonnull_pointers_only)
<< "nonnull" << Ex->getSourceRange();
continue;
}
-
+
NonNullArgs.push_back(x);
}
-
- // If no arguments were specified to __attribute__((nonnull)) then all
- // pointer arguments have a nonnull attribute.
+
+ // If no arguments were specified to __attribute__((nonnull)) then all pointer
+ // arguments have a nonnull attribute.
if (NonNullArgs.empty()) {
for (unsigned I = 0, E = getFunctionOrMethodNumArgs(d); I != E; ++I) {
QualType T = getFunctionOrMethodArgType(d, I);
- if (T->isPointerType() || T->isBlockPointerType())
+ if (T->isAnyPointerType() || T->isBlockPointerType())
NonNullArgs.push_back(I);
}
-
+
if (NonNullArgs.empty()) {
S.Diag(Attr.getLoc(), diag::warn_attribute_nonnull_no_pointers);
return;
@@ -389,26 +395,26 @@ static void HandleAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
return;
}
-
+
Expr *Arg = static_cast<Expr*>(Attr.getArg(0));
Arg = Arg->IgnoreParenCasts();
StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
-
+
if (Str == 0 || Str->isWide()) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
<< "alias" << 1;
return;
}
-
+
const char *Alias = Str->getStrData();
unsigned AliasLen = Str->getByteLength();
-
+
// FIXME: check if target symbol exists in current file
-
+
d->addAttr(::new (S.Context) AliasAttr(std::string(Alias, AliasLen)));
}
-static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr,
+static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr,
Sema &S) {
// check the attribute arguments.
if (Attr.getNumArgs() != 0) {
@@ -421,10 +427,28 @@ static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr,
<< Attr.getName() << 0 /*function*/;
return;
}
-
+
d->addAttr(::new (S.Context) AlwaysInlineAttr());
}
+static void HandleMallocAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(d)) {
+ QualType RetTy = FD->getResultType();
+ if (RetTy->isAnyPointerType() || RetTy->isBlockPointerType()) {
+ d->addAttr(::new (S.Context) MallocAttr());
+ return;
+ }
+ }
+
+ S.Diag(Attr.getLoc(), diag::warn_attribute_malloc_pointer_only);
+}
+
static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr,
Sema &S) {
// check the attribute arguments.
@@ -441,18 +465,18 @@ static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr,
return false;
}
}
-
+
return true;
}
static void HandleNoReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- if (HandleCommonNoReturnAttr(d, Attr, S))
+ if (HandleCommonNoReturnAttr(d, Attr, S))
d->addAttr(::new (S.Context) NoReturnAttr());
}
static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr,
Sema &S) {
- if (HandleCommonNoReturnAttr(d, Attr, S))
+ if (HandleCommonNoReturnAttr(d, Attr, S))
d->addAttr(::new (S.Context) AnalyzerNoReturnAttr());
}
@@ -462,13 +486,13 @@ static void HandleUnusedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
-
+
if (!isa<VarDecl>(d) && !isFunctionOrMethod(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << 2 /*variable and function*/;
return;
}
-
+
d->addAttr(::new (S.Context) UnusedAttr());
}
@@ -478,7 +502,7 @@ static void HandleUsedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
-
+
if (const VarDecl *VD = dyn_cast<VarDecl>(d)) {
if (VD->hasLocalStorage() || VD->hasExternalStorage()) {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "used";
@@ -489,7 +513,7 @@ static void HandleUsedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
<< Attr.getName() << 2 /*variable and function*/;
return;
}
-
+
d->addAttr(::new (S.Context) UsedAttr());
}
@@ -499,7 +523,7 @@ static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
<< "0 or 1";
return;
- }
+ }
int priority = 65535; // FIXME: Do not hardcode such constants.
if (Attr.getNumArgs() > 0) {
@@ -512,7 +536,7 @@ static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
priority = Idx.getZExtValue();
}
-
+
if (!isa<FunctionDecl>(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << 0 /*function*/;
@@ -528,7 +552,7 @@ static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
<< "0 or 1";
return;
- }
+ }
int priority = 65535; // FIXME: Do not hardcode such constants.
if (Attr.getNumArgs() > 0) {
@@ -541,7 +565,7 @@ static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
priority = Idx.getZExtValue();
}
-
+
if (!isa<FunctionDecl>(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << 0 /*function*/;
@@ -557,7 +581,7 @@ static void HandleDeprecatedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
-
+
d->addAttr(::new (S.Context) DeprecatedAttr());
}
@@ -567,7 +591,7 @@ static void HandleUnavailableAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
-
+
d->addAttr(::new (S.Context) UnavailableAttr());
}
@@ -577,21 +601,21 @@ static void HandleVisibilityAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
return;
}
-
+
Expr *Arg = static_cast<Expr*>(Attr.getArg(0));
Arg = Arg->IgnoreParenCasts();
StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
-
+
if (Str == 0 || Str->isWide()) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
<< "visibility" << 1;
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))
@@ -604,7 +628,7 @@ static void HandleVisibilityAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::warn_attribute_unknown_visibility) << TypeStr;
return;
}
-
+
d->addAttr(::new (S.Context) VisibilityAttr(type));
}
@@ -614,13 +638,13 @@ static void HandleObjCExceptionAttr(Decl *D, const AttributeList &Attr,
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 (S.Context) ObjCExceptionAttr());
}
@@ -632,7 +656,7 @@ static void HandleObjCNSObject(Decl *D, const AttributeList &Attr, Sema &S) {
if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
QualType T = TD->getUnderlyingType();
if (!T->isPointerType() ||
- !T->getAsPointerType()->getPointeeType()->isRecordType()) {
+ !T->getAs<PointerType>()->getPointeeType()->isRecordType()) {
S.Diag(TD->getLocation(), diag::err_nsobject_attribute);
return;
}
@@ -640,7 +664,7 @@ static void HandleObjCNSObject(Decl *D, const AttributeList &Attr, Sema &S) {
D->addAttr(::new (S.Context) ObjCNSObjectAttr());
}
-static void
+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;
@@ -656,17 +680,17 @@ HandleOverloadableAttr(Decl *D, const AttributeList &Attr, Sema &S) {
}
static void HandleBlocksAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- if (!Attr.getParameterName()) {
+ if (!Attr.getParameterName()) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
<< "blocks" << 1;
return;
}
-
+
if (Attr.getNumArgs() != 0) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
return;
}
-
+
BlocksAttr::BlocksAttrTypes type;
if (Attr.getParameterName()->isStr("byref"))
type = BlocksAttr::ByRef;
@@ -675,7 +699,7 @@ static void HandleBlocksAttr(Decl *d, const AttributeList &Attr, Sema &S) {
<< "blocks" << Attr.getParameterName();
return;
}
-
+
d->addAttr(::new (S.Context) BlocksAttr(type));
}
@@ -685,8 +709,8 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
<< "0, 1 or 2";
return;
- }
-
+ }
+
int sentinel = 0;
if (Attr.getNumArgs() > 0) {
Expr *E = static_cast<Expr *>(Attr.getArg(0));
@@ -697,7 +721,7 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
sentinel = Idx.getZExtValue();
-
+
if (sentinel < 0) {
S.Diag(Attr.getLoc(), diag::err_attribute_sentinel_less_than_zero)
<< E->getSourceRange();
@@ -715,7 +739,7 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
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.
@@ -726,39 +750,38 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(d)) {
- const FunctionType *FT = FD->getType()->getAsFunctionType();
+ const FunctionType *FT = FD->getType()->getAs<FunctionType>();
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()) {
S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0;
return;
- }
+ }
} else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(d)) {
if (!MD->isVariadic()) {
S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0;
return;
}
} else if (isa<BlockDecl>(d)) {
- // Note! BlockDecl is typeless. Variadic diagnostics
- // will be issued by the caller.
+ // Note! BlockDecl is typeless. Variadic diagnostics will be issued by the
+ // caller.
;
} else if (const VarDecl *V = dyn_cast<VarDecl>(d)) {
QualType Ty = V->getType();
if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) {
- const FunctionType *FT = Ty->isFunctionPointerType() ? getFunctionType(d)
- : Ty->getAsBlockPointerType()->getPointeeType()->getAsFunctionType();
+ const FunctionType *FT = Ty->isFunctionPointerType() ? getFunctionType(d)
+ : Ty->getAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>();
if (!cast<FunctionProtoType>(FT)->isVariadic()) {
int m = Ty->isFunctionPointerType() ? 0 : 1;
S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << m;
return;
}
- }
- else {
+ } else {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << 6 /*function, method or block */;
return;
@@ -785,7 +808,7 @@ static void HandleWarnUnusedResult(Decl *D, const AttributeList &Attr, Sema &S)
<< Attr.getName() << 0 /*function*/;
return;
}
-
+
Fn->addAttr(::new (S.Context) WarnUnusedResultAttr());
}
@@ -796,13 +819,26 @@ static void HandleWeakAttr(Decl *D, const AttributeList &Attr, Sema &S) {
return;
}
+ /* weak only applies to non-static declarations */
+ bool isStatic = false;
+ if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ isStatic = VD->getStorageClass() == VarDecl::Static;
+ } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ isStatic = FD->getStorageClass() == FunctionDecl::Static;
+ }
+ if (isStatic) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_weak_static) <<
+ dyn_cast<NamedDecl>(D)->getNameAsString();
+ return;
+ }
+
// TODO: could also be applied to methods?
if (!isa<FunctionDecl>(D) && !isa<VarDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << 2 /*variable and function*/;
return;
}
-
+
D->addAttr(::new (S.Context) WeakAttr());
}
@@ -811,7 +847,7 @@ static void HandleWeakImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
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;
@@ -830,7 +866,7 @@ static void HandleWeakImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
// Merge should handle any subsequent violations.
if (isDef) {
- S.Diag(Attr.getLoc(),
+ S.Diag(Attr.getLoc(),
diag::warn_attribute_weak_import_invalid_on_definition)
<< "weak_import" << 2 /*variable and function*/;
return;
@@ -904,8 +940,8 @@ static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
return;
}
- // Currently, the dllexport attribute is ignored for inlined functions,
- // unless the -fkeep-inline-functions flag has been used. Warning is emitted;
+ // 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";
@@ -947,15 +983,25 @@ static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) {
// 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)));
+ Expr *ArgExpr = static_cast<Expr *>(Attr.getArg(0));
+ StringLiteral *SE = dyn_cast<StringLiteral>(ArgExpr);
if (!SE) {
- // FIXME
- S.Diag(Attr.getLoc(), diag::err_attribute_annotate_no_string);
+ S.Diag(ArgExpr->getLocStart(), diag::err_attribute_not_string) << "section";
+ return;
+ }
+
+ std::string SectionStr(SE->getStrData(), SE->getByteLength());
+
+ // If the target wants to validate the section specifier, make it happen.
+ std::string Error = S.Context.Target.isValidSectionSpecifier(SectionStr);
+ if (Error.empty()) {
+ D->addAttr(::new (S.Context) SectionAttr(SectionStr));
return;
}
- D->addAttr(::new (S.Context) SectionAttr(std::string(SE->getStrData(),
- SE->getByteLength())));
+
+ S.Diag(SE->getLocStart(), diag::err_attribute_section_invalid_for_target)
+ << Error;
+
}
static void HandleStdCallAttr(Decl *d, const AttributeList &Attr, Sema &S) {
@@ -1011,7 +1057,7 @@ static void HandleNothrowAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
-
+
d->addAttr(::new (S.Context) NoThrowAttr());
}
@@ -1021,7 +1067,7 @@ static void HandleConstAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
-
+
d->addAttr(::new (S.Context) ConstAttr());
}
@@ -1031,7 +1077,7 @@ static void HandlePureAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
-
+
d->addAttr(::new (S.Context) PureAttr());
}
@@ -1039,33 +1085,34 @@ static void HandleCleanupAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// Match gcc which ignores cleanup attrs when compiling C++.
if (S.getLangOptions().CPlusPlus)
return;
-
- if (!Attr.getParameterName()) {
+
+ 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
- NamedDecl *CleanupDecl = S.LookupName(S.TUScope, Attr.getParameterName(),
- Sema::LookupOrdinaryName);
+ NamedDecl *CleanupDecl
+ = S.LookupSingleName(S.TUScope, Attr.getParameterName(),
+ Sema::LookupOrdinaryName);
if (!CleanupDecl) {
S.Diag(Attr.getLoc(), diag::err_attribute_cleanup_arg_not_found) <<
Attr.getParameterName();
return;
}
-
+
FunctionDecl *FD = dyn_cast<FunctionDecl>(CleanupDecl);
if (!FD) {
S.Diag(Attr.getLoc(), diag::err_attribute_cleanup_arg_not_function) <<
@@ -1078,24 +1125,24 @@ static void HandleCleanupAttr(Decl *d, const AttributeList &Attr, Sema &S) {
Attr.getParameterName();
return;
}
-
+
// 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();
if (S.CheckAssignmentConstraints(ParamTy, Ty) != Sema::Compatible) {
- S.Diag(Attr.getLoc(),
+ S.Diag(Attr.getLoc(),
diag::err_attribute_cleanup_func_arg_incompatible_type) <<
Attr.getParameterName() << ParamTy << Ty;
return;
}
-
+
d->addAttr(::new (S.Context) CleanupAttr(FD));
}
-/// Handle __attribute__((format_arg((idx)))) attribute
-/// based on http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
-static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+/// Handle __attribute__((format_arg((idx)))) attribute based on
+/// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
+static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) {
if (Attr.getNumArgs() != 1) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
return;
@@ -1105,9 +1152,8 @@ static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) {
<< Attr.getName() << 0 /*function*/;
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 with 1.
+ // FIXME: in C++ the implicit 'this' function parameter also counts. this is
+ // needed in order to be compatible with GCC the index must start with 1.
unsigned NumArgs = getFunctionOrMethodNumArgs(d);
unsigned FirstIdx = 1;
// checks for the 2nd argument
@@ -1118,46 +1164,46 @@ static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) {
<< "format" << 2 << IdxExpr->getSourceRange();
return;
}
-
+
if (Idx.getZExtValue() < FirstIdx || Idx.getZExtValue() > NumArgs) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
<< "format" << 2 << IdxExpr->getSourceRange();
return;
}
-
+
unsigned ArgIdx = Idx.getZExtValue() - 1;
-
+
// make sure the format string is really a string
QualType Ty = getFunctionOrMethodArgType(d, ArgIdx);
-
+
bool not_nsstring_type = !isNSStringType(Ty, S.Context);
if (not_nsstring_type &&
!isCFStringType(Ty, S.Context) &&
(!Ty->isPointerType() ||
- !Ty->getAsPointerType()->getPointeeType()->isCharType())) {
+ !Ty->getAs<PointerType>()->getPointeeType()->isCharType())) {
// FIXME: Should highlight the actual expression that has the wrong type.
S.Diag(Attr.getLoc(), diag::err_format_attribute_not)
- << (not_nsstring_type ? "a string type" : "an NSString")
+ << (not_nsstring_type ? "a string type" : "an NSString")
<< IdxExpr->getSourceRange();
return;
- }
+ }
Ty = getFunctionOrMethodResultType(d);
if (!isNSStringType(Ty, S.Context) &&
!isCFStringType(Ty, S.Context) &&
(!Ty->isPointerType() ||
- !Ty->getAsPointerType()->getPointeeType()->isCharType())) {
+ !Ty->getAs<PointerType>()->getPointeeType()->isCharType())) {
// FIXME: Should highlight the actual expression that has the wrong type.
S.Diag(Attr.getLoc(), diag::err_format_attribute_result_not)
- << (not_nsstring_type ? "string type" : "NSString")
+ << (not_nsstring_type ? "string type" : "NSString")
<< IdxExpr->getSourceRange();
return;
- }
-
+ }
+
d->addAttr(::new (S.Context) FormatArgAttr(Idx.getZExtValue()));
}
-/// Handle __attribute__((format(type,idx,firstarg))) attributes
-/// based on http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
+/// Handle __attribute__((format(type,idx,firstarg))) attributes based on
+/// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
if (!Attr.getParameterName()) {
@@ -1177,9 +1223,6 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
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
unsigned NumArgs = getFunctionOrMethodNumArgs(d);
unsigned FirstIdx = 1;
@@ -1197,19 +1240,23 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
bool is_NSString = false;
bool is_strftime = false;
bool is_CFString = false;
-
+
switch (FormatLen) {
default: break;
case 5: Supported = !memcmp(Format, "scanf", 5); break;
case 6: Supported = !memcmp(Format, "printf", 6); break;
- case 7: Supported = !memcmp(Format, "strfmon", 7); break;
+ case 7: Supported = !memcmp(Format, "printf0", 7) ||
+ !memcmp(Format, "strfmon", 7) ||
+ !memcmp(Format, "cmn_err", 7); break;
case 8:
Supported = (is_strftime = !memcmp(Format, "strftime", 8)) ||
(is_NSString = !memcmp(Format, "NSString", 8)) ||
+ !memcmp(Format, "vcmn_err", 8) ||
+ !memcmp(Format, "zcmn_err", 8) ||
(is_CFString = !memcmp(Format, "CFString", 8));
break;
}
-
+
if (!Supported) {
S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported)
<< "format" << Attr.getParameterName()->getName();
@@ -1225,6 +1272,16 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
+ // FIXME: We should handle the implicit 'this' parameter in a more generic
+ // way that can be used for other arguments.
+ bool HasImplicitThisParam = false;
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(d)) {
+ if (MD->isInstance()) {
+ HasImplicitThisParam = true;
+ NumArgs++;
+ }
+ }
+
if (Idx.getZExtValue() < FirstIdx || Idx.getZExtValue() > NumArgs) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
<< "format" << 2 << IdxExpr->getSourceRange();
@@ -1233,7 +1290,9 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// FIXME: Do we need to bounds check?
unsigned ArgIdx = Idx.getZExtValue() - 1;
-
+
+ if (HasImplicitThisParam) ArgIdx--;
+
// make sure the format string is really a string
QualType Ty = getFunctionOrMethodArgType(d, ArgIdx);
@@ -1251,9 +1310,9 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_format_attribute_not)
<< "an NSString" << IdxExpr->getSourceRange();
return;
- }
+ }
} else if (!Ty->isPointerType() ||
- !Ty->getAsPointerType()->getPointeeType()->isCharType()) {
+ !Ty->getAs<PointerType>()->getPointeeType()->isCharType()) {
// FIXME: Should highlight the actual expression that has the wrong type.
S.Diag(Attr.getLoc(), diag::err_format_attribute_not)
<< "a string type" << IdxExpr->getSourceRange();
@@ -1321,7 +1380,7 @@ static void HandleTransparentUnionAttr(Decl *d, const AttributeList &Attr,
}
if (!RD->isDefinition()) {
- S.Diag(Attr.getLoc(),
+ S.Diag(Attr.getLoc(),
diag::warn_transparent_union_attribute_not_definition);
return;
}
@@ -1336,7 +1395,7 @@ static void HandleTransparentUnionAttr(Decl *d, const AttributeList &Attr,
FieldDecl *FirstField = *Field;
QualType FirstType = FirstField->getType();
if (FirstType->isFloatingType() || FirstType->isVectorType()) {
- S.Diag(FirstField->getLocation(),
+ S.Diag(FirstField->getLocation(),
diag::warn_transparent_union_attribute_floating);
return;
}
@@ -1349,13 +1408,13 @@ static void HandleTransparentUnionAttr(Decl *d, const AttributeList &Attr,
S.Context.getTypeAlign(FieldType) != FirstAlign) {
// Warn if we drop the attribute.
bool isSize = S.Context.getTypeSize(FieldType) != FirstSize;
- unsigned FieldBits = isSize? S.Context.getTypeSize(FieldType)
+ unsigned FieldBits = isSize? S.Context.getTypeSize(FieldType)
: S.Context.getTypeAlign(FieldType);
- S.Diag(Field->getLocation(),
+ S.Diag(Field->getLocation(),
diag::warn_transparent_union_attribute_field_size_align)
<< isSize << Field->getDeclName() << FieldBits;
unsigned FirstBits = isSize? FirstSize : FirstAlign;
- S.Diag(FirstField->getLocation(),
+ S.Diag(FirstField->getLocation(),
diag::note_transparent_union_first_field_size_align)
<< isSize << FirstBits;
return;
@@ -1371,13 +1430,13 @@ static void HandleAnnotateAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
return;
}
- Expr *argExpr = static_cast<Expr *>(Attr.getArg(0));
- StringLiteral *SE = dyn_cast<StringLiteral>(argExpr);
-
+ Expr *ArgExpr = static_cast<Expr *>(Attr.getArg(0));
+ StringLiteral *SE = dyn_cast<StringLiteral>(ArgExpr);
+
// Make sure that there is a string literal as the annotation's single
// argument.
if (!SE) {
- S.Diag(Attr.getLoc(), diag::err_attribute_annotate_no_string);
+ S.Diag(ArgExpr->getLocStart(), diag::err_attribute_not_string) <<"annotate";
return;
}
d->addAttr(::new (S.Context) AnnotateAttr(std::string(SE->getStrData(),
@@ -1399,7 +1458,7 @@ static void HandleAlignedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
d->addAttr(::new (S.Context) AlignedAttr(Align));
return;
}
-
+
Expr *alignmentExpr = static_cast<Expr *>(Attr.getArg(0));
llvm::APSInt Alignment(32);
if (!alignmentExpr->isIntegerConstantExpr(Alignment, S.Context)) {
@@ -1408,7 +1467,7 @@ static void HandleAlignedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
if (!llvm::isPowerOf2_64(Alignment.getZExtValue())) {
- S.Diag(Attr.getLoc(), diag::err_attribute_aligned_not_power_of_two)
+ S.Diag(Attr.getLoc(), diag::err_attribute_aligned_not_power_of_two)
<< alignmentExpr->getSourceRange();
return;
}
@@ -1416,13 +1475,12 @@ static void HandleAlignedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
d->addAttr(::new (S.Context) AlignedAttr(Alignment.getZExtValue() * 8));
}
-/// HandleModeAttr - This attribute modifies the width of a decl with
-/// primitive type.
-///
-/// 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.
+/// HandleModeAttr - This attribute modifies the width of a decl with primitive
+/// type.
///
+/// 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.
static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
// This attribute isn't documented, but glibc uses it. It changes
// the width of an int or unsigned int to the specified size.
@@ -1495,7 +1553,7 @@ static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
return;
}
- if (!OldTy->getAsBuiltinType() && !OldTy->isComplexType())
+ if (!OldTy->getAs<BuiltinType>() && !OldTy->isComplexType())
S.Diag(Attr.getLoc(), diag::err_mode_not_primitive);
else if (IntegerMode) {
if (!OldTy->isIntegralType())
@@ -1581,7 +1639,7 @@ static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
cast<ValueDecl>(D)->setType(NewTy);
}
-static void HandleNodebugAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+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;
@@ -1593,24 +1651,24 @@ static void HandleNodebugAttr(Decl *d, const AttributeList &Attr, Sema &S) {
<< Attr.getName() << 0 /*function*/;
return;
}
-
- d->addAttr(::new (S.Context) NodebugAttr());
+
+ d->addAttr(::new (S.Context) NoDebugAttr());
}
-static void HandleNoinlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+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 (!isa<FunctionDecl>(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << 0 /*function*/;
return;
}
-
- d->addAttr(::new (S.Context) NoinlineAttr());
+
+ d->addAttr(::new (S.Context) NoInlineAttr());
}
static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
@@ -1619,19 +1677,19 @@ static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
-
+
FunctionDecl *Fn = dyn_cast<FunctionDecl>(d);
if (Fn == 0) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << 0 /*function*/;
return;
}
-
+
if (!Fn->isInline()) {
S.Diag(Attr.getLoc(), diag::warn_gnu_inline_attribute_requires_inline);
return;
}
-
+
d->addAttr(::new (S.Context) GNUInlineAttr());
}
@@ -1679,23 +1737,26 @@ static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &Attr,
Sema &S) {
QualType RetTy;
-
+
if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(d))
RetTy = MD->getResultType();
else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(d))
RetTy = FD->getResultType();
else {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 3 /* function or method */;
+ SourceLocation L = Attr.getLoc();
+ S.Diag(d->getLocStart(), diag::warn_attribute_wrong_decl_type)
+ << SourceRange(L, L) << Attr.getName() << 3 /* function or method */;
return;
}
-
- if (!(S.Context.isObjCNSObjectType(RetTy) || RetTy->getAsPointerType())) {
- S.Diag(Attr.getLoc(), diag::warn_ns_attribute_wrong_return_type)
- << Attr.getName();
- return;
+
+ if (!(S.Context.isObjCNSObjectType(RetTy) || RetTy->getAs<PointerType>()
+ || RetTy->getAs<ObjCObjectPointerType>())) {
+ SourceLocation L = Attr.getLoc();
+ S.Diag(d->getLocStart(), diag::warn_ns_attribute_wrong_return_type)
+ << SourceRange(L, L) << Attr.getName();
+ return;
}
-
+
switch (Attr.getKind()) {
default:
assert(0 && "invalid ownership attribute");
@@ -1716,7 +1777,8 @@ static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &Attr,
/// ProcessDeclAttribute - Apply the specific attribute to the specified decl if
/// the attribute applies to decls. If the attribute is a type attribute, just
/// silently ignore it.
-static void ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Attr, Sema &S) {
+static void ProcessDeclAttribute(Scope *scope, Decl *D,
+ const AttributeList &Attr, Sema &S) {
if (Attr.isDeclspecAttribute())
// FIXME: Try to deal with __declspec attributes!
return;
@@ -1724,14 +1786,15 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Att
case AttributeList::AT_IBOutlet: HandleIBOutletAttr (D, Attr, S); break;
case AttributeList::AT_address_space:
case AttributeList::AT_objc_gc:
- // Ignore these, these are type attributes, handled by ProcessTypeAttributes.
+ // Ignore these, these are type attributes, handled by
+ // ProcessTypeAttributes.
break;
case AttributeList::AT_alias: HandleAliasAttr (D, Attr, S); break;
case AttributeList::AT_aligned: HandleAlignedAttr (D, Attr, S); break;
- case AttributeList::AT_always_inline:
+ case AttributeList::AT_always_inline:
HandleAlwaysInlineAttr (D, Attr, S); break;
case AttributeList::AT_analyzer_noreturn:
- HandleAnalyzerNoReturnAttr (D, Attr, S); break;
+ HandleAnalyzerNoReturnAttr (D, Attr, S); break;
case AttributeList::AT_annotate: HandleAnnotateAttr (D, Attr, S); break;
case AttributeList::AT_constructor: HandleConstructorAttr(D, Attr, S); break;
case AttributeList::AT_deprecated: HandleDeprecatedAttr(D, Attr, S); break;
@@ -1746,6 +1809,7 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Att
case AttributeList::AT_format_arg: HandleFormatArgAttr (D, Attr, S); break;
case AttributeList::AT_gnu_inline: HandleGNUInlineAttr(D, Attr, S); break;
case AttributeList::AT_mode: HandleModeAttr (D, Attr, S); break;
+ case AttributeList::AT_malloc: HandleMallocAttr (D, Attr, S); break;
case AttributeList::AT_nonnull: HandleNonNullAttr (D, Attr, S); break;
case AttributeList::AT_noreturn: HandleNoReturnAttr (D, Attr, S); break;
case AttributeList::AT_nothrow: HandleNothrowAttr (D, Attr, S); break;
@@ -1783,10 +1847,10 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Att
case AttributeList::AT_const: HandleConstAttr (D, Attr, S); break;
case AttributeList::AT_pure: HandlePureAttr (D, Attr, S); break;
case AttributeList::AT_cleanup: HandleCleanupAttr (D, Attr, S); break;
- case AttributeList::AT_nodebug: HandleNodebugAttr (D, Attr, S); break;
- case AttributeList::AT_noinline: HandleNoinlineAttr (D, Attr, S); break;
+ case AttributeList::AT_nodebug: HandleNoDebugAttr (D, Attr, S); break;
+ case AttributeList::AT_noinline: HandleNoInlineAttr (D, Attr, S); break;
case AttributeList::AT_regparm: HandleRegparmAttr (D, Attr, S); break;
- case AttributeList::IgnoredAttribute:
+ case AttributeList::IgnoredAttribute:
case AttributeList::AT_no_instrument_function: // Interacts with -pg.
// Just ignore
break;
@@ -1805,14 +1869,66 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *Attr
}
}
+/// DeclClonePragmaWeak - clone existing decl (maybe definition),
+/// #pragma weak needs a non-definition decl and source may not have one
+NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II) {
+ assert(isa<FunctionDecl>(ND) || isa<VarDecl>(ND));
+ NamedDecl *NewD = 0;
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
+ NewD = FunctionDecl::Create(FD->getASTContext(), FD->getDeclContext(),
+ FD->getLocation(), DeclarationName(II),
+ FD->getType(), FD->getDeclaratorInfo());
+ } else if (VarDecl *VD = dyn_cast<VarDecl>(ND)) {
+ NewD = VarDecl::Create(VD->getASTContext(), VD->getDeclContext(),
+ VD->getLocation(), II,
+ VD->getType(), VD->getDeclaratorInfo(),
+ VD->getStorageClass());
+ }
+ return NewD;
+}
+
+/// DeclApplyPragmaWeak - A declaration (maybe definition) needs #pragma weak
+/// applied to it, possibly with an alias.
+void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) {
+ if (W.getUsed()) return; // only do this once
+ W.setUsed(true);
+ if (W.getAlias()) { // clone decl, impersonate __attribute(weak,alias(...))
+ IdentifierInfo *NDId = ND->getIdentifier();
+ NamedDecl *NewD = DeclClonePragmaWeak(ND, W.getAlias());
+ NewD->addAttr(::new (Context) AliasAttr(NDId->getName()));
+ NewD->addAttr(::new (Context) WeakAttr());
+ WeakTopLevelDecl.push_back(NewD);
+ // FIXME: "hideous" code from Sema::LazilyCreateBuiltin
+ // to insert Decl at TU scope, sorry.
+ DeclContext *SavedContext = CurContext;
+ CurContext = Context.getTranslationUnitDecl();
+ PushOnScopeChains(NewD, S);
+ CurContext = SavedContext;
+ } else { // just add weak to existing
+ ND->addAttr(::new (Context) WeakAttr());
+ }
+}
+
/// 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(Scope *S, Decl *D, const Declarator &PD) {
+ // Handle #pragma weak
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
+ if (ND->hasLinkage()) {
+ WeakInfo W = WeakUndeclaredIdentifiers.lookup(ND->getIdentifier());
+ if (W != WeakInfo()) {
+ // Identifier referenced by #pragma weak before it was declared
+ DeclApplyPragmaWeak(S, ND, W);
+ WeakUndeclaredIdentifiers[ND->getIdentifier()] = W;
+ }
+ }
+ }
+
// Apply decl attributes from the DeclSpec if present.
if (const AttributeList *Attrs = PD.getDeclSpec().getAttributes())
ProcessDeclAttributeList(S, D, Attrs);
-
+
// 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;
@@ -1820,7 +1936,7 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) {
for (unsigned i = 0, e = PD.getNumTypeObjects(); i != e; ++i)
if (const AttributeList *Attrs = PD.getTypeObject(i).getAttrs())
ProcessDeclAttributeList(S, D, Attrs);
-
+
// Finally, apply any attributes on the decl itself.
if (const AttributeList *Attrs = PD.getAttributes())
ProcessDeclAttributeList(S, D, Attrs);