diff options
Diffstat (limited to 'lib/Sema/SemaDeclAttr.cpp')
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 544 |
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); |