diff --git a/clang/clang.xcodeproj/project.pbxproj b/clang/clang.xcodeproj/project.pbxproj index 17d0042884fa..bb9935ade9a3 100644 --- a/clang/clang.xcodeproj/project.pbxproj +++ b/clang/clang.xcodeproj/project.pbxproj @@ -62,6 +62,7 @@ DE224FF80C7AA98800D370A5 /* CGExprComplex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE224FF70C7AA98800D370A5 /* CGExprComplex.cpp */; }; DE2252700C7E82D000D370A5 /* CGExprScalar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE22526F0C7E82D000D370A5 /* CGExprScalar.cpp */; }; DE2255FC0C8004E600D370A5 /* ParseDeclCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE2255FB0C8004E600D370A5 /* ParseDeclCXX.cpp */; }; + DE22BCF20E14197E0094DC60 /* SemaDeclAttr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE22BCF10E14197E0094DC60 /* SemaDeclAttr.cpp */; }; DE344AB80AE5DF6D00DBC861 /* HeaderSearch.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE344AB70AE5DF6D00DBC861 /* HeaderSearch.h */; }; DE344B540AE5E46C00DBC861 /* HeaderSearch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE344B530AE5E46C00DBC861 /* HeaderSearch.cpp */; }; DE3450D70AEB543100DBC861 /* DirectoryLookup.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE3450D60AEB543100DBC861 /* DirectoryLookup.h */; }; @@ -346,6 +347,7 @@ DE224FF70C7AA98800D370A5 /* CGExprComplex.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CGExprComplex.cpp; path = lib/CodeGen/CGExprComplex.cpp; sourceTree = ""; }; DE22526F0C7E82D000D370A5 /* CGExprScalar.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CGExprScalar.cpp; path = lib/CodeGen/CGExprScalar.cpp; sourceTree = ""; }; DE2255FB0C8004E600D370A5 /* ParseDeclCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ParseDeclCXX.cpp; path = lib/Parse/ParseDeclCXX.cpp; sourceTree = ""; }; + DE22BCF10E14197E0094DC60 /* SemaDeclAttr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SemaDeclAttr.cpp; path = lib/Sema/SemaDeclAttr.cpp; sourceTree = ""; }; DE344AB70AE5DF6D00DBC861 /* HeaderSearch.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = HeaderSearch.h; sourceTree = ""; }; DE344B530AE5E46C00DBC861 /* HeaderSearch.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = HeaderSearch.cpp; sourceTree = ""; }; DE3450D60AEB543100DBC861 /* DirectoryLookup.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DirectoryLookup.h; sourceTree = ""; }; @@ -688,6 +690,7 @@ DE67E7160C020EE400F66BC5 /* Sema.cpp */, DEF2F00F0C6CFED5000C4259 /* SemaChecking.cpp */, DE67E7120C020ED900F66BC5 /* SemaDecl.cpp */, + DE22BCF10E14197E0094DC60 /* SemaDeclAttr.cpp */, 35EF676F0DAD1D2C00B19414 /* SemaDeclCXX.cpp */, DE704B250D0FBEBE009C7762 /* SemaDeclObjC.cpp */, DE67E7100C020ED400F66BC5 /* SemaExpr.cpp */, @@ -1111,6 +1114,7 @@ 35EE48B10E0C4CCA00715C54 /* DeclCXX.cpp in Sources */, 35EE48B20E0C4CCA00715C54 /* ParentMap.cpp in Sources */, 3534A01D0E129849002709B2 /* ParseCXXInlineMethods.cpp in Sources */, + DE22BCF20E14197E0094DC60 /* SemaDeclAttr.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index b954c8b2e114..0b048b0a0afe 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -19,13 +19,13 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/Type.h" #include "clang/Parse/DeclSpec.h" #include "clang/Parse/Scope.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/SourceManager.h" -#include "clang/AST/ExprCXX.h" // FIXME: layering (ideally, Sema shouldn't be dependent on Lex API's) #include "clang/Lex/Preprocessor.h" #include "clang/Lex/HeaderSearch.h" @@ -260,7 +260,8 @@ TypedefDecl *Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) { return New; } -/// DeclhasAttr - returns true if decl Declaration already has the target attribute. +/// DeclhasAttr - returns true if decl Declaration already has the target +/// attribute. static bool DeclHasAttr(const Decl *decl, const Attr *target) { for (const Attr *attr = decl->getAttrs(); attr; attr = attr->getNext()) if (attr->getKind() == target->getKind()) @@ -2325,673 +2326,3 @@ Sema::DeclTy* Sema::ActOnLinkageSpec(SourceLocation Loc, // FIXME: Add all the various semantics of linkage specifications return LinkageSpecDecl::Create(Context, Loc, Language, dcl); } - -void Sema::HandleDeclAttribute(Decl *New, const AttributeList *Attr) { - - switch (Attr->getKind()) { - case AttributeList::AT_vector_size: - if (ValueDecl *vDecl = dyn_cast(New)) { - QualType newType = HandleVectorTypeAttribute(vDecl->getType(), Attr); - if (!newType.isNull()) // install the new vector type into the decl - vDecl->setType(newType); - } - if (TypedefDecl *tDecl = dyn_cast(New)) { - QualType newType = HandleVectorTypeAttribute(tDecl->getUnderlyingType(), - Attr); - if (!newType.isNull()) // install the new vector type into the decl - tDecl->setUnderlyingType(newType); - } - break; - case AttributeList::AT_ext_vector_type: - if (TypedefDecl *tDecl = dyn_cast(New)) - HandleExtVectorTypeAttribute(tDecl, Attr); - else - Diag(Attr->getLoc(), - diag::err_typecheck_ext_vector_not_typedef); - break; - case AttributeList::AT_address_space: - // Ignore this, this is a type attribute, handled by ProcessTypeAttributes. - break; - case AttributeList::AT_mode: - // 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. - if (TypedefDecl *tDecl = dyn_cast(New)) { - QualType newType = HandleModeTypeAttribute(tDecl->getUnderlyingType(), - Attr); - tDecl->setUnderlyingType(newType); - } else if (ValueDecl *vDecl = dyn_cast(New)) { - QualType newType = HandleModeTypeAttribute(vDecl->getType(), Attr); - vDecl->setType(newType); - } - // FIXME: Diagnostic? - break; - case AttributeList::AT_alias: - HandleAliasAttribute(New, Attr); - break; - case AttributeList::AT_deprecated: - HandleDeprecatedAttribute(New, Attr); - break; - case AttributeList::AT_visibility: - HandleVisibilityAttribute(New, Attr); - break; - case AttributeList::AT_weak: - HandleWeakAttribute(New, Attr); - break; - case AttributeList::AT_dllimport: - HandleDLLImportAttribute(New, Attr); - break; - case AttributeList::AT_dllexport: - HandleDLLExportAttribute(New, Attr); - break; - case AttributeList::AT_nothrow: - HandleNothrowAttribute(New, Attr); - break; - case AttributeList::AT_stdcall: - HandleStdCallAttribute(New, Attr); - break; - case AttributeList::AT_fastcall: - HandleFastCallAttribute(New, Attr); - break; - case AttributeList::AT_aligned: - HandleAlignedAttribute(New, Attr); - break; - case AttributeList::AT_packed: - HandlePackedAttribute(New, Attr); - break; - case AttributeList::AT_annotate: - HandleAnnotateAttribute(New, Attr); - break; - case AttributeList::AT_noreturn: - HandleNoReturnAttribute(New, Attr); - break; - case AttributeList::AT_format: - HandleFormatAttribute(New, Attr); - break; - case AttributeList::AT_transparent_union: - HandleTransparentUnionAttribute(New, Attr); - break; - default: -#if 0 - // TODO: when we have the full set of attributes, warn about unknown ones. - Diag(Attr->getLoc(), diag::warn_attribute_ignored, - Attr->getName()->getName()); -#endif - break; - } -} - -void Sema::HandleDeclAttributes(Decl *New, const AttributeList *DeclSpecAttrs, - const AttributeList *DeclaratorAttrs) { - if (DeclSpecAttrs == 0 && DeclaratorAttrs == 0) return; - - while (DeclSpecAttrs) { - HandleDeclAttribute(New, DeclSpecAttrs); - DeclSpecAttrs = DeclSpecAttrs->getNext(); - } - - // If there are any type attributes that were in the declarator, apply them to - // its top level type. - if (ValueDecl *VD = dyn_cast(New)) { - QualType DT = VD->getType(); - ProcessTypeAttributes(DT, DeclaratorAttrs); - VD->setType(DT); - } else if (TypedefDecl *TD = dyn_cast(New)) { - QualType DT = TD->getUnderlyingType(); - ProcessTypeAttributes(DT, DeclaratorAttrs); - TD->setUnderlyingType(DT); - } - - while (DeclaratorAttrs) { - HandleDeclAttribute(New, DeclaratorAttrs); - DeclaratorAttrs = DeclaratorAttrs->getNext(); - } -} - -void Sema::HandleExtVectorTypeAttribute(TypedefDecl *tDecl, - const AttributeList *rawAttr) { - QualType curType = tDecl->getUnderlyingType(); - // check the attribute arguments. - if (rawAttr->getNumArgs() != 1) { - Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, - std::string("1")); - return; - } - Expr *sizeExpr = static_cast(rawAttr->getArg(0)); - llvm::APSInt vecSize(32); - if (!sizeExpr->isIntegerConstantExpr(vecSize, Context)) { - Diag(rawAttr->getLoc(), diag::err_attribute_argument_not_int, - "ext_vector_type", sizeExpr->getSourceRange()); - return; - } - // unlike gcc's vector_size attribute, we do not allow vectors to be defined - // in conjunction with complex types (pointers, arrays, functions, etc.). - Type *canonType = curType.getCanonicalType().getTypePtr(); - if (!(canonType->isIntegerType() || canonType->isRealFloatingType())) { - Diag(rawAttr->getLoc(), diag::err_attribute_invalid_vector_type, - curType.getCanonicalType().getAsString()); - return; - } - // unlike gcc's vector_size attribute, the size is specified as the - // number of elements, not the number of bytes. - unsigned vectorSize = static_cast(vecSize.getZExtValue()); - - if (vectorSize == 0) { - Diag(rawAttr->getLoc(), diag::err_attribute_zero_size, - sizeExpr->getSourceRange()); - return; - } - // Instantiate/Install the vector type, the number of elements is > 0. - tDecl->setUnderlyingType(Context.getExtVectorType(curType, vectorSize)); - // Remember this typedef decl, we will need it later for diagnostics. - ExtVectorDecls.push_back(tDecl); -} - -QualType Sema::HandleVectorTypeAttribute(QualType curType, - const AttributeList *rawAttr) { - // check the attribute arugments. - if (rawAttr->getNumArgs() != 1) { - Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, - std::string("1")); - return QualType(); - } - Expr *sizeExpr = static_cast(rawAttr->getArg(0)); - llvm::APSInt vecSize(32); - if (!sizeExpr->isIntegerConstantExpr(vecSize, Context)) { - Diag(rawAttr->getLoc(), diag::err_attribute_argument_not_int, - "vector_size", sizeExpr->getSourceRange()); - return QualType(); - } - // navigate to the base type - we need to provide for vector pointers, - // vector arrays, and functions returning vectors. - Type *canonType = curType.getCanonicalType().getTypePtr(); - - if (canonType->isPointerType() || canonType->isArrayType() || - canonType->isFunctionType()) { - assert(0 && "HandleVector(): Complex type construction unimplemented"); - /* FIXME: rebuild the type from the inside out, vectorizing the inner type. - do { - if (PointerType *PT = dyn_cast(canonType)) - canonType = PT->getPointeeType().getTypePtr(); - else if (ArrayType *AT = dyn_cast(canonType)) - canonType = AT->getElementType().getTypePtr(); - else if (FunctionType *FT = dyn_cast(canonType)) - canonType = FT->getResultType().getTypePtr(); - } while (canonType->isPointerType() || canonType->isArrayType() || - canonType->isFunctionType()); - */ - } - // the base type must be integer or float. - if (!(canonType->isIntegerType() || canonType->isRealFloatingType())) { - Diag(rawAttr->getLoc(), diag::err_attribute_invalid_vector_type, - curType.getCanonicalType().getAsString()); - return QualType(); - } - unsigned typeSize = static_cast(Context.getTypeSize(curType)); - // vecSize is specified in bytes - convert to bits. - unsigned vectorSize = static_cast(vecSize.getZExtValue() * 8); - - // the vector size needs to be an integral multiple of the type size. - if (vectorSize % typeSize) { - Diag(rawAttr->getLoc(), diag::err_attribute_invalid_size, - sizeExpr->getSourceRange()); - return QualType(); - } - if (vectorSize == 0) { - Diag(rawAttr->getLoc(), diag::err_attribute_zero_size, - sizeExpr->getSourceRange()); - return QualType(); - } - // Instantiate the vector type, the number of elements is > 0, and not - // required to be a power of 2, unlike GCC. - return Context.getVectorType(curType, vectorSize/typeSize); -} - -void Sema::HandlePackedAttribute(Decl *d, const AttributeList *rawAttr) { - // check the attribute arguments. - if (rawAttr->getNumArgs() > 0) { - Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, - std::string("0")); - return; - } - - if (TagDecl *TD = dyn_cast(d)) - TD->addAttr(new PackedAttr); - else if (FieldDecl *FD = dyn_cast(d)) { - // If the alignment is less than or equal to 8 bits, the packed attribute - // has no effect. - if (!FD->getType()->isIncompleteType() && - Context.getTypeAlign(FD->getType()) <= 8) - Diag(rawAttr->getLoc(), - diag::warn_attribute_ignored_for_field_of_type, - rawAttr->getName()->getName(), FD->getType().getAsString()); - else - FD->addAttr(new PackedAttr); - } else - Diag(rawAttr->getLoc(), diag::warn_attribute_ignored, - rawAttr->getName()->getName()); -} - -void Sema::HandleAliasAttribute(Decl *d, const AttributeList *rawAttr) { - // check the attribute arguments. - if (rawAttr->getNumArgs() != 1) { - Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, - std::string("1")); - return; - } - - Expr *Arg = static_cast(rawAttr->getArg(0)); - Arg = Arg->IgnoreParenCasts(); - StringLiteral *Str = dyn_cast(Arg); - - if (Str == 0 || Str->isWide()) { - Diag(rawAttr->getLoc(), diag::err_attribute_argument_n_not_string, - "alias", std::string("1")); - return; - } - - const char *Alias = Str->getStrData(); - unsigned AliasLen = Str->getByteLength(); - - // FIXME: check if target symbol exists in current file - - d->addAttr(new AliasAttr(std::string(Alias, AliasLen))); -} - -void Sema::HandleNoReturnAttribute(Decl *d, const AttributeList *rawAttr) { - // check the attribute arguments. - if (rawAttr->getNumArgs() != 0) { - Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, - std::string("0")); - return; - } - - FunctionDecl *Fn = dyn_cast(d); - - if (!Fn) { - Diag(rawAttr->getLoc(), diag::warn_attribute_wrong_decl_type, - "noreturn", "function"); - return; - } - - d->addAttr(new NoReturnAttr()); -} - -void Sema::HandleDeprecatedAttribute(Decl *d, const AttributeList *rawAttr) { - // check the attribute arguments. - if (rawAttr->getNumArgs() != 0) { - Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, - std::string("0")); - return; - } - - d->addAttr(new DeprecatedAttr()); -} - -void Sema::HandleVisibilityAttribute(Decl *d, const AttributeList *rawAttr) { - // check the attribute arguments. - if (rawAttr->getNumArgs() != 1) { - Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, - std::string("1")); - return; - } - - Expr *Arg = static_cast(rawAttr->getArg(0)); - Arg = Arg->IgnoreParenCasts(); - StringLiteral *Str = dyn_cast(Arg); - - if (Str == 0 || Str->isWide()) { - Diag(rawAttr->getLoc(), diag::err_attribute_argument_n_not_string, - "visibility", std::string("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)) - type = VisibilityAttr::HiddenVisibility; - else if (TypeLen == 8 && !memcmp(TypeStr, "internal", 8)) - type = VisibilityAttr::HiddenVisibility; // FIXME - else if (TypeLen == 9 && !memcmp(TypeStr, "protected", 9)) - type = VisibilityAttr::ProtectedVisibility; - else { - Diag(rawAttr->getLoc(), diag::warn_attribute_type_not_supported, - "visibility", TypeStr); - return; - } - - d->addAttr(new VisibilityAttr(type)); -} - -void Sema::HandleWeakAttribute(Decl *d, const AttributeList *rawAttr) { - // check the attribute arguments. - if (rawAttr->getNumArgs() != 0) { - Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, - std::string("0")); - return; - } - - d->addAttr(new WeakAttr()); -} - -void Sema::HandleDLLImportAttribute(Decl *d, const AttributeList *rawAttr) { - // check the attribute arguments. - if (rawAttr->getNumArgs() != 0) { - Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, - std::string("0")); - return; - } - - d->addAttr(new DLLImportAttr()); -} - -void Sema::HandleDLLExportAttribute(Decl *d, const AttributeList *rawAttr) { - // check the attribute arguments. - if (rawAttr->getNumArgs() != 0) { - Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, - std::string("0")); - return; - } - - d->addAttr(new DLLExportAttr()); -} - -void Sema::HandleStdCallAttribute(Decl *d, const AttributeList *rawAttr) { - // check the attribute arguments. - if (rawAttr->getNumArgs() != 0) { - Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, - std::string("0")); - return; - } - - d->addAttr(new StdCallAttr()); -} - -void Sema::HandleFastCallAttribute(Decl *d, const AttributeList *rawAttr) { - // check the attribute arguments. - if (rawAttr->getNumArgs() != 0) { - Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, - std::string("0")); - return; - } - - d->addAttr(new FastCallAttr()); -} - -void Sema::HandleNothrowAttribute(Decl *d, const AttributeList *rawAttr) { - // check the attribute arguments. - if (rawAttr->getNumArgs() != 0) { - Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, - std::string("0")); - return; - } - - d->addAttr(new NoThrowAttr()); -} - -static const FunctionTypeProto *getFunctionProto(Decl *d) { - QualType Ty; - - if (ValueDecl *decl = dyn_cast(d)) - Ty = decl->getType(); - else if (FieldDecl *decl = dyn_cast(d)) - Ty = decl->getType(); - else if (TypedefDecl* decl = dyn_cast(d)) - Ty = decl->getUnderlyingType(); - else - return 0; - - if (Ty->isFunctionPointerType()) { - const PointerType *PtrTy = Ty->getAsPointerType(); - Ty = PtrTy->getPointeeType(); - } - - if (const FunctionType *FnTy = Ty->getAsFunctionType()) - return dyn_cast(FnTy->getAsFunctionType()); - - return 0; -} - -static inline bool isNSStringType(QualType T, ASTContext &Ctx) { - if (!T->isPointerType()) - return false; - - T = T->getAsPointerType()->getPointeeType().getCanonicalType(); - ObjCInterfaceType* ClsT = dyn_cast(T.getTypePtr()); - - 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"); -} - -/// Handle __attribute__((format(type,idx,firstarg))) attributes -/// based on http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html -void Sema::HandleFormatAttribute(Decl *d, const AttributeList *rawAttr) { - - if (!rawAttr->getParameterName()) { - Diag(rawAttr->getLoc(), diag::err_attribute_argument_n_not_string, - "format", std::string("1")); - return; - } - - if (rawAttr->getNumArgs() != 2) { - Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, - std::string("3")); - return; - } - - // GCC ignores the format attribute on K&R style function - // prototypes, so we ignore it as well - const FunctionTypeProto *proto = getFunctionProto(d); - - if (!proto) { - Diag(rawAttr->getLoc(), diag::warn_attribute_wrong_decl_type, - "format", "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 in 1 and the limit is numargs+1 - unsigned NumArgs = proto->getNumArgs(); - unsigned FirstIdx = 1; - - const char *Format = rawAttr->getParameterName()->getName(); - unsigned FormatLen = rawAttr->getParameterName()->getLength(); - - // Normalize the argument, __foo__ becomes foo. - if (FormatLen > 4 && Format[0] == '_' && Format[1] == '_' && - Format[FormatLen - 2] == '_' && Format[FormatLen - 1] == '_') { - Format += 2; - FormatLen -= 4; - } - - bool Supported = false; - bool is_NSString = false; - bool is_strftime = false; - - 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 8: - Supported = (is_strftime = !memcmp(Format, "strftime", 8)) || - (is_NSString = !memcmp(Format, "NSString", 8)); - break; - } - - if (!Supported) { - Diag(rawAttr->getLoc(), diag::warn_attribute_type_not_supported, - "format", rawAttr->getParameterName()->getName()); - return; - } - - // checks for the 2nd argument - Expr *IdxExpr = static_cast(rawAttr->getArg(0)); - llvm::APSInt Idx(Context.getTypeSize(IdxExpr->getType())); - if (!IdxExpr->isIntegerConstantExpr(Idx, Context)) { - Diag(rawAttr->getLoc(), diag::err_attribute_argument_n_not_int, - "format", std::string("2"), IdxExpr->getSourceRange()); - return; - } - - if (Idx.getZExtValue() < FirstIdx || Idx.getZExtValue() > NumArgs) { - Diag(rawAttr->getLoc(), diag::err_attribute_argument_out_of_bounds, - "format", std::string("2"), IdxExpr->getSourceRange()); - return; - } - - // FIXME: Do we need to bounds check? - unsigned ArgIdx = Idx.getZExtValue() - 1; - - // make sure the format string is really a string - QualType Ty = proto->getArgType(ArgIdx); - - if (is_NSString) { - // FIXME: do we need to check if the type is NSString*? What are - // the semantics? - if (!isNSStringType(Ty, Context)) { - // FIXME: Should highlight the actual expression that has the - // wrong type. - Diag(rawAttr->getLoc(), diag::err_format_attribute_not_NSString, - IdxExpr->getSourceRange()); - return; - } - } - else if (!Ty->isPointerType() || - !Ty->getAsPointerType()->getPointeeType()->isCharType()) { - // FIXME: Should highlight the actual expression that has the - // wrong type. - Diag(rawAttr->getLoc(), diag::err_format_attribute_not_string, - IdxExpr->getSourceRange()); - return; - } - - // check the 3rd argument - Expr *FirstArgExpr = static_cast(rawAttr->getArg(1)); - llvm::APSInt FirstArg(Context.getTypeSize(FirstArgExpr->getType())); - if (!FirstArgExpr->isIntegerConstantExpr(FirstArg, Context)) { - Diag(rawAttr->getLoc(), diag::err_attribute_argument_n_not_int, - "format", std::string("3"), FirstArgExpr->getSourceRange()); - return; - } - - // check if the function is variadic if the 3rd argument non-zero - if (FirstArg != 0) { - if (proto->isVariadic()) { - ++NumArgs; // +1 for ... - } else { - Diag(d->getLocation(), diag::err_format_attribute_requires_variadic); - return; - } - } - - // strftime requires FirstArg to be 0 because it doesn't read from any variable - // the input is just the current time + the format string - if (is_strftime) { - if (FirstArg != 0) { - Diag(rawAttr->getLoc(), diag::err_format_strftime_third_parameter, - FirstArgExpr->getSourceRange()); - return; - } - // if 0 it disables parameter checking (to use with e.g. va_list) - } else if (FirstArg != 0 && FirstArg != NumArgs) { - Diag(rawAttr->getLoc(), diag::err_attribute_argument_out_of_bounds, - "format", std::string("3"), FirstArgExpr->getSourceRange()); - return; - } - - d->addAttr(new FormatAttr(std::string(Format, FormatLen), - Idx.getZExtValue(), FirstArg.getZExtValue())); -} - -void Sema::HandleTransparentUnionAttribute(Decl *d, - const AttributeList *rawAttr) { - // check the attribute arguments. - if (rawAttr->getNumArgs() != 0) { - Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, - std::string("0")); - return; - } - - TypeDecl *decl = dyn_cast(d); - - if (!decl || !Context.getTypeDeclType(decl)->isUnionType()) { - Diag(rawAttr->getLoc(), diag::warn_attribute_wrong_decl_type, - "transparent_union", "union"); - return; - } - - //QualType QTy = Context.getTypeDeclType(decl); - //const RecordType *Ty = QTy->getAsUnionType(); - -// FIXME -// Ty->addAttr(new TransparentUnionAttr()); -} - -void Sema::HandleAnnotateAttribute(Decl *d, const AttributeList *rawAttr) { - // check the attribute arguments. - if (rawAttr->getNumArgs() != 1) { - Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, - std::string("1")); - return; - } - Expr *argExpr = static_cast(rawAttr->getArg(0)); - StringLiteral *SE = dyn_cast(argExpr); - - // Make sure that there is a string literal as the annotation's single - // argument. - if (!SE) { - Diag(rawAttr->getLoc(), diag::err_attribute_annotate_no_string); - return; - } - d->addAttr(new AnnotateAttr(std::string(SE->getStrData(), - SE->getByteLength()))); -} - -void Sema::HandleAlignedAttribute(Decl *d, const AttributeList *rawAttr) -{ - // check the attribute arguments. - if (rawAttr->getNumArgs() > 1) { - Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, - std::string("1")); - return; - } - - unsigned Align = 0; - - if (rawAttr->getNumArgs() == 0) { - // FIXME: This should be the target specific maximum alignment. - // (For now we just use 128 bits which is the maximum on X86. - Align = 128; - return; - } else { - Expr *alignmentExpr = static_cast(rawAttr->getArg(0)); - llvm::APSInt alignment(32); - if (!alignmentExpr->isIntegerConstantExpr(alignment, Context)) { - Diag(rawAttr->getLoc(), diag::err_attribute_argument_not_int, - "aligned", alignmentExpr->getSourceRange()); - return; - } - - Align = alignment.getZExtValue() * 8; - } - - d->addAttr(new AlignedAttr(Align)); -} diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp new file mode 100644 index 000000000000..8d715f1cdcd8 --- /dev/null +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -0,0 +1,655 @@ +//===--- SemaDeclAttr.cpp - Declaration Attribute Handling ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements decl-related attribute processing. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" +#include "clang/AST/ASTContext.h" + +using namespace clang; + +static const FunctionTypeProto *getFunctionProto(Decl *d) { + QualType Ty; + + if (ValueDecl *decl = dyn_cast(d)) + Ty = decl->getType(); + else if (FieldDecl *decl = dyn_cast(d)) + Ty = decl->getType(); + else if (TypedefDecl* decl = dyn_cast(d)) + Ty = decl->getUnderlyingType(); + else + return 0; + + if (Ty->isFunctionPointerType()) + Ty = Ty->getAsPointerType()->getPointeeType(); + + if (const FunctionType *FnTy = Ty->getAsFunctionType()) + return dyn_cast(FnTy->getAsFunctionType()); + + return 0; +} + +static inline bool isNSStringType(QualType T, ASTContext &Ctx) { + if (!T->isPointerType()) + return false; + + T = T->getAsPointerType()->getPointeeType().getCanonicalType(); + ObjCInterfaceType* ClsT = dyn_cast(T.getTypePtr()); + + 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"); +} + +void Sema::HandleDeclAttribute(Decl *New, const AttributeList *Attr) { + + switch (Attr->getKind()) { + case AttributeList::AT_vector_size: + if (ValueDecl *vDecl = dyn_cast(New)) { + QualType newType = HandleVectorTypeAttribute(vDecl->getType(), Attr); + if (!newType.isNull()) // install the new vector type into the decl + vDecl->setType(newType); + } + if (TypedefDecl *tDecl = dyn_cast(New)) { + QualType newType = HandleVectorTypeAttribute(tDecl->getUnderlyingType(), + Attr); + if (!newType.isNull()) // install the new vector type into the decl + tDecl->setUnderlyingType(newType); + } + break; + case AttributeList::AT_ext_vector_type: + if (TypedefDecl *tDecl = dyn_cast(New)) + HandleExtVectorTypeAttribute(tDecl, Attr); + else + Diag(Attr->getLoc(), + diag::err_typecheck_ext_vector_not_typedef); + break; + case AttributeList::AT_address_space: + // Ignore this, this is a type attribute, handled by ProcessTypeAttributes. + break; + case AttributeList::AT_mode: + // 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. + if (TypedefDecl *tDecl = dyn_cast(New)) { + QualType newType = HandleModeTypeAttribute(tDecl->getUnderlyingType(), + Attr); + tDecl->setUnderlyingType(newType); + } else if (ValueDecl *vDecl = dyn_cast(New)) { + QualType newType = HandleModeTypeAttribute(vDecl->getType(), Attr); + vDecl->setType(newType); + } + // FIXME: Diagnostic? + break; + case AttributeList::AT_alias: HandleAliasAttribute(New, Attr); break; + case AttributeList::AT_deprecated: HandleDeprecatedAttribute(New, Attr);break; + case AttributeList::AT_visibility: HandleVisibilityAttribute(New, Attr);break; + case AttributeList::AT_weak: HandleWeakAttribute(New, Attr); break; + case AttributeList::AT_dllimport: HandleDLLImportAttribute(New, Attr); break; + case AttributeList::AT_dllexport: HandleDLLExportAttribute(New, Attr); break; + case AttributeList::AT_nothrow: HandleNothrowAttribute(New, Attr); break; + case AttributeList::AT_stdcall: HandleStdCallAttribute(New, Attr); break; + case AttributeList::AT_fastcall: HandleFastCallAttribute(New, Attr); break; + case AttributeList::AT_aligned: HandleAlignedAttribute(New, Attr); break; + case AttributeList::AT_packed: HandlePackedAttribute(New, Attr); break; + case AttributeList::AT_annotate: HandleAnnotateAttribute(New, Attr); break; + case AttributeList::AT_noreturn: HandleNoReturnAttribute(New, Attr); break; + case AttributeList::AT_format: HandleFormatAttribute(New, Attr); break; + case AttributeList::AT_transparent_union: + HandleTransparentUnionAttribute(New, Attr); + break; + default: +#if 0 + // TODO: when we have the full set of attributes, warn about unknown ones. + Diag(Attr->getLoc(), diag::warn_attribute_ignored, + Attr->getName()->getName()); +#endif + break; + } +} + +void Sema::HandleDeclAttributes(Decl *New, const AttributeList *DeclSpecAttrs, + const AttributeList *DeclaratorAttrs) { + if (DeclSpecAttrs == 0 && DeclaratorAttrs == 0) return; + + while (DeclSpecAttrs) { + HandleDeclAttribute(New, DeclSpecAttrs); + DeclSpecAttrs = DeclSpecAttrs->getNext(); + } + + // If there are any type attributes that were in the declarator, apply them to + // its top level type. + if (ValueDecl *VD = dyn_cast(New)) { + QualType DT = VD->getType(); + ProcessTypeAttributes(DT, DeclaratorAttrs); + VD->setType(DT); + } else if (TypedefDecl *TD = dyn_cast(New)) { + QualType DT = TD->getUnderlyingType(); + ProcessTypeAttributes(DT, DeclaratorAttrs); + TD->setUnderlyingType(DT); + } + + while (DeclaratorAttrs) { + HandleDeclAttribute(New, DeclaratorAttrs); + DeclaratorAttrs = DeclaratorAttrs->getNext(); + } +} + +void Sema::HandleExtVectorTypeAttribute(TypedefDecl *tDecl, + const AttributeList *rawAttr) { + QualType curType = tDecl->getUnderlyingType(); + // check the attribute arguments. + if (rawAttr->getNumArgs() != 1) { + Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, + std::string("1")); + return; + } + Expr *sizeExpr = static_cast(rawAttr->getArg(0)); + llvm::APSInt vecSize(32); + if (!sizeExpr->isIntegerConstantExpr(vecSize, Context)) { + Diag(rawAttr->getLoc(), diag::err_attribute_argument_not_int, + "ext_vector_type", sizeExpr->getSourceRange()); + return; + } + // unlike gcc's vector_size attribute, we do not allow vectors to be defined + // in conjunction with complex types (pointers, arrays, functions, etc.). + Type *canonType = curType.getCanonicalType().getTypePtr(); + if (!(canonType->isIntegerType() || canonType->isRealFloatingType())) { + Diag(rawAttr->getLoc(), diag::err_attribute_invalid_vector_type, + curType.getCanonicalType().getAsString()); + return; + } + // unlike gcc's vector_size attribute, the size is specified as the + // number of elements, not the number of bytes. + unsigned vectorSize = static_cast(vecSize.getZExtValue()); + + if (vectorSize == 0) { + Diag(rawAttr->getLoc(), diag::err_attribute_zero_size, + sizeExpr->getSourceRange()); + return; + } + // Instantiate/Install the vector type, the number of elements is > 0. + tDecl->setUnderlyingType(Context.getExtVectorType(curType, vectorSize)); + // Remember this typedef decl, we will need it later for diagnostics. + ExtVectorDecls.push_back(tDecl); +} + +QualType Sema::HandleVectorTypeAttribute(QualType curType, + const AttributeList *rawAttr) { + // check the attribute arugments. + if (rawAttr->getNumArgs() != 1) { + Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, + std::string("1")); + return QualType(); + } + Expr *sizeExpr = static_cast(rawAttr->getArg(0)); + llvm::APSInt vecSize(32); + if (!sizeExpr->isIntegerConstantExpr(vecSize, Context)) { + Diag(rawAttr->getLoc(), diag::err_attribute_argument_not_int, + "vector_size", sizeExpr->getSourceRange()); + return QualType(); + } + // navigate to the base type - we need to provide for vector pointers, + // vector arrays, and functions returning vectors. + Type *canonType = curType.getCanonicalType().getTypePtr(); + + if (canonType->isPointerType() || canonType->isArrayType() || + canonType->isFunctionType()) { + assert(0 && "HandleVector(): Complex type construction unimplemented"); + /* FIXME: rebuild the type from the inside out, vectorizing the inner type. + do { + if (PointerType *PT = dyn_cast(canonType)) + canonType = PT->getPointeeType().getTypePtr(); + else if (ArrayType *AT = dyn_cast(canonType)) + canonType = AT->getElementType().getTypePtr(); + else if (FunctionType *FT = dyn_cast(canonType)) + canonType = FT->getResultType().getTypePtr(); + } while (canonType->isPointerType() || canonType->isArrayType() || + canonType->isFunctionType()); + */ + } + // the base type must be integer or float. + if (!(canonType->isIntegerType() || canonType->isRealFloatingType())) { + Diag(rawAttr->getLoc(), diag::err_attribute_invalid_vector_type, + curType.getCanonicalType().getAsString()); + return QualType(); + } + unsigned typeSize = static_cast(Context.getTypeSize(curType)); + // vecSize is specified in bytes - convert to bits. + unsigned vectorSize = static_cast(vecSize.getZExtValue() * 8); + + // the vector size needs to be an integral multiple of the type size. + if (vectorSize % typeSize) { + Diag(rawAttr->getLoc(), diag::err_attribute_invalid_size, + sizeExpr->getSourceRange()); + return QualType(); + } + if (vectorSize == 0) { + Diag(rawAttr->getLoc(), diag::err_attribute_zero_size, + sizeExpr->getSourceRange()); + return QualType(); + } + // Instantiate the vector type, the number of elements is > 0, and not + // required to be a power of 2, unlike GCC. + return Context.getVectorType(curType, vectorSize/typeSize); +} + +void Sema::HandlePackedAttribute(Decl *d, const AttributeList *rawAttr) { + // check the attribute arguments. + if (rawAttr->getNumArgs() > 0) { + Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, + std::string("0")); + return; + } + + if (TagDecl *TD = dyn_cast(d)) + TD->addAttr(new PackedAttr); + else if (FieldDecl *FD = dyn_cast(d)) { + // If the alignment is less than or equal to 8 bits, the packed attribute + // has no effect. + if (!FD->getType()->isIncompleteType() && + Context.getTypeAlign(FD->getType()) <= 8) + Diag(rawAttr->getLoc(), + diag::warn_attribute_ignored_for_field_of_type, + rawAttr->getName()->getName(), FD->getType().getAsString()); + else + FD->addAttr(new PackedAttr); + } else + Diag(rawAttr->getLoc(), diag::warn_attribute_ignored, + rawAttr->getName()->getName()); +} + +void Sema::HandleAliasAttribute(Decl *d, const AttributeList *rawAttr) { + // check the attribute arguments. + if (rawAttr->getNumArgs() != 1) { + Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, + std::string("1")); + return; + } + + Expr *Arg = static_cast(rawAttr->getArg(0)); + Arg = Arg->IgnoreParenCasts(); + StringLiteral *Str = dyn_cast(Arg); + + if (Str == 0 || Str->isWide()) { + Diag(rawAttr->getLoc(), diag::err_attribute_argument_n_not_string, + "alias", std::string("1")); + return; + } + + const char *Alias = Str->getStrData(); + unsigned AliasLen = Str->getByteLength(); + + // FIXME: check if target symbol exists in current file + + d->addAttr(new AliasAttr(std::string(Alias, AliasLen))); +} + +void Sema::HandleNoReturnAttribute(Decl *d, const AttributeList *rawAttr) { + // check the attribute arguments. + if (rawAttr->getNumArgs() != 0) { + Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, + std::string("0")); + return; + } + + FunctionDecl *Fn = dyn_cast(d); + + if (!Fn) { + Diag(rawAttr->getLoc(), diag::warn_attribute_wrong_decl_type, + "noreturn", "function"); + return; + } + + d->addAttr(new NoReturnAttr()); +} + +void Sema::HandleDeprecatedAttribute(Decl *d, const AttributeList *rawAttr) { + // check the attribute arguments. + if (rawAttr->getNumArgs() != 0) { + Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, + std::string("0")); + return; + } + + d->addAttr(new DeprecatedAttr()); +} + +void Sema::HandleVisibilityAttribute(Decl *d, const AttributeList *rawAttr) { + // check the attribute arguments. + if (rawAttr->getNumArgs() != 1) { + Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, + std::string("1")); + return; + } + + Expr *Arg = static_cast(rawAttr->getArg(0)); + Arg = Arg->IgnoreParenCasts(); + StringLiteral *Str = dyn_cast(Arg); + + if (Str == 0 || Str->isWide()) { + Diag(rawAttr->getLoc(), diag::err_attribute_argument_n_not_string, + "visibility", std::string("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)) + type = VisibilityAttr::HiddenVisibility; + else if (TypeLen == 8 && !memcmp(TypeStr, "internal", 8)) + type = VisibilityAttr::HiddenVisibility; // FIXME + else if (TypeLen == 9 && !memcmp(TypeStr, "protected", 9)) + type = VisibilityAttr::ProtectedVisibility; + else { + Diag(rawAttr->getLoc(), diag::warn_attribute_type_not_supported, + "visibility", TypeStr); + return; + } + + d->addAttr(new VisibilityAttr(type)); +} + +void Sema::HandleWeakAttribute(Decl *d, const AttributeList *rawAttr) { + // check the attribute arguments. + if (rawAttr->getNumArgs() != 0) { + Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, + std::string("0")); + return; + } + + d->addAttr(new WeakAttr()); +} + +void Sema::HandleDLLImportAttribute(Decl *d, const AttributeList *rawAttr) { + // check the attribute arguments. + if (rawAttr->getNumArgs() != 0) { + Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, + std::string("0")); + return; + } + + d->addAttr(new DLLImportAttr()); +} + +void Sema::HandleDLLExportAttribute(Decl *d, const AttributeList *rawAttr) { + // check the attribute arguments. + if (rawAttr->getNumArgs() != 0) { + Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, + std::string("0")); + return; + } + + d->addAttr(new DLLExportAttr()); +} + +void Sema::HandleStdCallAttribute(Decl *d, const AttributeList *rawAttr) { + // check the attribute arguments. + if (rawAttr->getNumArgs() != 0) { + Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, + std::string("0")); + return; + } + + d->addAttr(new StdCallAttr()); +} + +void Sema::HandleFastCallAttribute(Decl *d, const AttributeList *rawAttr) { + // check the attribute arguments. + if (rawAttr->getNumArgs() != 0) { + Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, + std::string("0")); + return; + } + + d->addAttr(new FastCallAttr()); +} + +void Sema::HandleNothrowAttribute(Decl *d, const AttributeList *rawAttr) { + // check the attribute arguments. + if (rawAttr->getNumArgs() != 0) { + Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, + std::string("0")); + return; + } + + d->addAttr(new NoThrowAttr()); +} + +/// Handle __attribute__((format(type,idx,firstarg))) attributes +/// based on http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html +void Sema::HandleFormatAttribute(Decl *d, const AttributeList *rawAttr) { + + if (!rawAttr->getParameterName()) { + Diag(rawAttr->getLoc(), diag::err_attribute_argument_n_not_string, + "format", std::string("1")); + return; + } + + if (rawAttr->getNumArgs() != 2) { + Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, + std::string("3")); + return; + } + + // GCC ignores the format attribute on K&R style function + // prototypes, so we ignore it as well + const FunctionTypeProto *proto = getFunctionProto(d); + + if (!proto) { + Diag(rawAttr->getLoc(), diag::warn_attribute_wrong_decl_type, + "format", "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 in 1 and the limit is numargs+1 + unsigned NumArgs = proto->getNumArgs(); + unsigned FirstIdx = 1; + + const char *Format = rawAttr->getParameterName()->getName(); + unsigned FormatLen = rawAttr->getParameterName()->getLength(); + + // Normalize the argument, __foo__ becomes foo. + if (FormatLen > 4 && Format[0] == '_' && Format[1] == '_' && + Format[FormatLen - 2] == '_' && Format[FormatLen - 1] == '_') { + Format += 2; + FormatLen -= 4; + } + + bool Supported = false; + bool is_NSString = false; + bool is_strftime = false; + + 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 8: + Supported = (is_strftime = !memcmp(Format, "strftime", 8)) || + (is_NSString = !memcmp(Format, "NSString", 8)); + break; + } + + if (!Supported) { + Diag(rawAttr->getLoc(), diag::warn_attribute_type_not_supported, + "format", rawAttr->getParameterName()->getName()); + return; + } + + // checks for the 2nd argument + Expr *IdxExpr = static_cast(rawAttr->getArg(0)); + llvm::APSInt Idx(Context.getTypeSize(IdxExpr->getType())); + if (!IdxExpr->isIntegerConstantExpr(Idx, Context)) { + Diag(rawAttr->getLoc(), diag::err_attribute_argument_n_not_int, + "format", std::string("2"), IdxExpr->getSourceRange()); + return; + } + + if (Idx.getZExtValue() < FirstIdx || Idx.getZExtValue() > NumArgs) { + Diag(rawAttr->getLoc(), diag::err_attribute_argument_out_of_bounds, + "format", std::string("2"), IdxExpr->getSourceRange()); + return; + } + + // FIXME: Do we need to bounds check? + unsigned ArgIdx = Idx.getZExtValue() - 1; + + // make sure the format string is really a string + QualType Ty = proto->getArgType(ArgIdx); + + if (is_NSString) { + // FIXME: do we need to check if the type is NSString*? What are + // the semantics? + if (!isNSStringType(Ty, Context)) { + // FIXME: Should highlight the actual expression that has the + // wrong type. + Diag(rawAttr->getLoc(), diag::err_format_attribute_not_NSString, + IdxExpr->getSourceRange()); + return; + } + } else if (!Ty->isPointerType() || + !Ty->getAsPointerType()->getPointeeType()->isCharType()) { + // FIXME: Should highlight the actual expression that has the + // wrong type. + Diag(rawAttr->getLoc(), diag::err_format_attribute_not_string, + IdxExpr->getSourceRange()); + return; + } + + // check the 3rd argument + Expr *FirstArgExpr = static_cast(rawAttr->getArg(1)); + llvm::APSInt FirstArg(Context.getTypeSize(FirstArgExpr->getType())); + if (!FirstArgExpr->isIntegerConstantExpr(FirstArg, Context)) { + Diag(rawAttr->getLoc(), diag::err_attribute_argument_n_not_int, + "format", std::string("3"), FirstArgExpr->getSourceRange()); + return; + } + + // check if the function is variadic if the 3rd argument non-zero + if (FirstArg != 0) { + if (proto->isVariadic()) { + ++NumArgs; // +1 for ... + } else { + Diag(d->getLocation(), diag::err_format_attribute_requires_variadic); + return; + } + } + + // strftime requires FirstArg to be 0 because it doesn't read from any variable + // the input is just the current time + the format string + if (is_strftime) { + if (FirstArg != 0) { + Diag(rawAttr->getLoc(), diag::err_format_strftime_third_parameter, + FirstArgExpr->getSourceRange()); + return; + } + // if 0 it disables parameter checking (to use with e.g. va_list) + } else if (FirstArg != 0 && FirstArg != NumArgs) { + Diag(rawAttr->getLoc(), diag::err_attribute_argument_out_of_bounds, + "format", std::string("3"), FirstArgExpr->getSourceRange()); + return; + } + + d->addAttr(new FormatAttr(std::string(Format, FormatLen), + Idx.getZExtValue(), FirstArg.getZExtValue())); +} + +void Sema::HandleTransparentUnionAttribute(Decl *d, + const AttributeList *rawAttr) { + // check the attribute arguments. + if (rawAttr->getNumArgs() != 0) { + Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, + std::string("0")); + return; + } + + TypeDecl *decl = dyn_cast(d); + + if (!decl || !Context.getTypeDeclType(decl)->isUnionType()) { + Diag(rawAttr->getLoc(), diag::warn_attribute_wrong_decl_type, + "transparent_union", "union"); + return; + } + + //QualType QTy = Context.getTypeDeclType(decl); + //const RecordType *Ty = QTy->getAsUnionType(); + +// FIXME +// Ty->addAttr(new TransparentUnionAttr()); +} + +void Sema::HandleAnnotateAttribute(Decl *d, const AttributeList *rawAttr) { + // check the attribute arguments. + if (rawAttr->getNumArgs() != 1) { + Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, + std::string("1")); + return; + } + Expr *argExpr = static_cast(rawAttr->getArg(0)); + StringLiteral *SE = dyn_cast(argExpr); + + // Make sure that there is a string literal as the annotation's single + // argument. + if (!SE) { + Diag(rawAttr->getLoc(), diag::err_attribute_annotate_no_string); + return; + } + d->addAttr(new AnnotateAttr(std::string(SE->getStrData(), + SE->getByteLength()))); +} + +void Sema::HandleAlignedAttribute(Decl *d, const AttributeList *rawAttr) { + // check the attribute arguments. + if (rawAttr->getNumArgs() > 1) { + Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, + std::string("1")); + return; + } + + unsigned Align = 0; + + if (rawAttr->getNumArgs() == 0) { + // FIXME: This should be the target specific maximum alignment. + // (For now we just use 128 bits which is the maximum on X86. + Align = 128; + return; + } else { + Expr *alignmentExpr = static_cast(rawAttr->getArg(0)); + llvm::APSInt alignment(32); + if (!alignmentExpr->isIntegerConstantExpr(alignment, Context)) { + Diag(rawAttr->getLoc(), diag::err_attribute_argument_not_int, + "aligned", alignmentExpr->getSourceRange()); + return; + } + + Align = alignment.getZExtValue() * 8; + } + + d->addAttr(new AlignedAttr(Align)); +}