Index: test/CodeGen/noreturn.c =================================================================== --- test/CodeGen/noreturn.c (revision 0) +++ test/CodeGen/noreturn.c (revision 0) @@ -0,0 +1,4 @@ +// RUN: clang -emit-llvm < %s | grep noreturn + +void f() __attribute__((noreturn)); +void f() {} Index: test/CodeGen/nothrow.c =================================================================== --- test/CodeGen/nothrow.c (revision 0) +++ test/CodeGen/nothrow.c (revision 0) @@ -0,0 +1,4 @@ +// RUN: clang -emit-llvm < %s | grep nounwind + +void f() __attribute__((nothrow)); +void f() {} Index: test/CodeGen/weak-function.c =================================================================== --- test/CodeGen/weak-function.c (revision 0) +++ test/CodeGen/weak-function.c (revision 0) @@ -0,0 +1,4 @@ +// RUN: clang -emit-llvm < %s | grep weak + +void f() __attribute__((weak)); +void f() {} Index: test/CodeGen/function-visibility.c =================================================================== --- test/CodeGen/function-visibility.c (revision 0) +++ test/CodeGen/function-visibility.c (revision 0) @@ -0,0 +1,4 @@ +// RUN: clang -emit-llvm < %s | grep hidden + +void f() __attribute__((visibility(hidden))); +void f() {} Index: test/CodeGen/weak-var.c =================================================================== --- test/CodeGen/weak-var.c (revision 0) +++ test/CodeGen/weak-var.c (revision 0) @@ -0,0 +1,3 @@ +// RUN: clang -emit-llvm < %s | grep weak + +int i __attribute__((weak)) = 2; Index: test/CodeGen/var-visibility.c =================================================================== --- test/CodeGen/var-visibility.c (revision 0) +++ test/CodeGen/var-visibility.c (revision 0) @@ -0,0 +1,3 @@ +// RUN: clang -emit-llvm < %s | grep protected + +int globalvar __attribute__((visibility(protected))); Index: test/Sema/deprecated.c =================================================================== --- test/Sema/deprecated.c (revision 47826) +++ test/Sema/deprecated.c (working copy) @@ -13,7 +13,7 @@ f(); // expected-warning {{'f' is deprecated}} // test if attributes propagate to functions - g(); // todo-warning {{'g' is deprecated}} + g(); // expected-warning {{'g' is deprecated}} return var; // expected-warning {{'var' is deprecated}} } @@ -21,5 +21,5 @@ // test if attributes propagate to variables extern int var; int w() { - return var; // todo-warning {{'var' is deprecated}} + return var; // expected-warning {{'var' is deprecated}} } Index: include/clang/Basic/DiagnosticKinds.def =================================================================== --- include/clang/Basic/DiagnosticKinds.def (revision 47826) +++ include/clang/Basic/DiagnosticKinds.def (working copy) @@ -567,6 +567,14 @@ "invalid vector type '%0'") DIAG(err_attribute_argument_not_int, ERROR, "'%0' attribute requires integer constant") +DIAG(err_attribute_argument_n_not_int, ERROR, + "'%0' attribute requires parameter %1 to be an integer constant") +DIAG(err_attribute_argument_n_not_string, ERROR, + "'%0' attribute requires parameter %1 to be a string") +DIAG(err_attribute_argument_out_of_bounds, ERROR, + "'%0' attribute parameter %1 is out of bounds") +DIAG(err_format_strftime_third_parameter, ERROR, + "strftime format attribute requires 3rd parameter to be 0") DIAG(err_attribute_invalid_size, ERROR, "vector size not an integral multiple of component size") DIAG(err_attribute_zero_size, ERROR, @@ -589,8 +597,12 @@ "argument to annotate attribute was not a string literal") DIAG(warn_attribute_ignored, WARNING, "'%0' attribute ignored") +DIAG(warn_attribute_wrong_decl_type, WARNING, + "'%0' attribute only applies to %1 types") DIAG(warn_attribute_ignored_for_field_of_type, WARNING, "'%0' attribute ignored for field of type '%1'") +DIAG(warn_attribute_type_not_supported, WARNING, + "'%0' attribute argument not supported: '%1'") // Function Parameter Semantic Analysis. DIAG(err_param_with_void_type, ERROR, Index: include/clang/AST/Attr.h =================================================================== --- include/clang/AST/Attr.h (revision 47826) +++ include/clang/AST/Attr.h (working copy) @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_AST_ATTR_H #define LLVM_CLANG_AST_ATTR_H +#include "llvm/GlobalValue.h" #include #include @@ -27,7 +28,13 @@ Packed, Annotate, NoReturn, - Deprecated + Deprecated, + Weak, + DLLImport, + DLLExport, + NoThrow, + Format, + Visibility }; private: @@ -118,6 +125,77 @@ static bool classof(const DeprecatedAttr *A) { return true; } }; +class WeakAttr : public Attr { +public: + WeakAttr() : Attr(Weak) {} + + // Implement isa/cast/dyncast/etc. + + static bool classof(const Attr *A) { return A->getKind() == Weak; } + static bool classof(const WeakAttr *A) { return true; } +}; + +class NoThrowAttr : public Attr { +public: + NoThrowAttr() : Attr(NoThrow) {} + + // Implement isa/cast/dyncast/etc. + + static bool classof(const Attr *A) { return A->getKind() == NoThrow; } + static bool classof(const NoThrowAttr *A) { return true; } +}; + +class FormatAttr : public Attr { + std::string Type; + int formatIdx, firstArg; +public: + FormatAttr(const std::string &type, int idx, int first) : Attr(Format), + Type(type), formatIdx(idx), firstArg(first) {} + + const std::string& getType() const { return Type; } + int getFormatIdx() const { return formatIdx; } + int getFirstArg() const { return firstArg; } + + // Implement isa/cast/dyncast/etc. + + static bool classof(const Attr *A) { return A->getKind() == Format; } + static bool classof(const FormatAttr *A) { return true; } +}; + +class VisibilityAttr : public Attr { + llvm::GlobalValue::VisibilityTypes VisibilityType; +public: + VisibilityAttr(llvm::GlobalValue::VisibilityTypes v) : Attr(Visibility), + VisibilityType(v) {} + + llvm::GlobalValue::VisibilityTypes getVisibility() const { return VisibilityType; } + + // Implement isa/cast/dyncast/etc. + + static bool classof(const Attr *A) { return A->getKind() == Visibility; } + static bool classof(const VisibilityAttr *A) { return true; } +}; + +class DLLImportAttr : public Attr { +public: + DLLImportAttr() : Attr(DLLImport) {} + + // Implement isa/cast/dyncast/etc. + + static bool classof(const Attr *A) { return A->getKind() == DLLImport; } + static bool classof(const DLLImportAttr *A) { return true; } +}; + +class DLLExportAttr : public Attr { +public: + DLLExportAttr() : Attr(DLLExport) {} + + // Implement isa/cast/dyncast/etc. + + static bool classof(const Attr *A) { return A->getKind() == DLLExport; } + static bool classof(const DLLExportAttr *A) { return true; } +}; + } // end namespace clang #endif Index: include/clang/Parse/AttributeList.h =================================================================== --- include/clang/Parse/AttributeList.h (revision 47826) +++ include/clang/Parse/AttributeList.h (working copy) @@ -50,7 +50,19 @@ AT_packed, AT_annotate, AT_noreturn, - AT_deprecated + AT_deprecated, + AT_unused, + AT_format, + AT_nonnull, + AT_malloc, + AT_pure, + AT_weak, + AT_dllimport, + AT_dllexport, + AT_visibility, + AT_nothrow, + AT_noinline, + AT_warn_unused_result }; IdentifierInfo *getName() const { return AttrName; } Index: Sema/Sema.h =================================================================== --- Sema/Sema.h (revision 47826) +++ Sema/Sema.h (working copy) @@ -273,6 +273,13 @@ void HandlePackedAttribute(Decl *d, AttributeList *rawAttr); void HandleAnnotateAttribute(Decl *d, AttributeList *rawAttr); void HandleNoReturnAttribute(Decl *d, AttributeList *rawAttr); + void HandleDeprecatedAttribute(Decl *d, AttributeList *rawAttr); + void HandleWeakAttribute(Decl *d, AttributeList *rawAttr); + void HandleDLLImportAttribute(Decl *d, AttributeList *rawAttr); + void HandleDLLExportAttribute(Decl *d, AttributeList *rawAttr); + void HandleVisibilityAttribute(Decl *d, AttributeList *rawAttr); + void HandleNothrowAttribute(Decl *d, AttributeList *rawAttr); + void HandleFormatAttribute(Decl *d, AttributeList *rawAttr); void WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method, bool &IncompleteImpl); Index: Sema/SemaDecl.cpp =================================================================== --- Sema/SemaDecl.cpp (revision 47826) +++ Sema/SemaDecl.cpp (working copy) @@ -242,6 +242,33 @@ return New; } +/// 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()) + return true; + + return false; +} + +/// MergeAttributes - append attributes from the Old decl to the New one. +static void MergeAttributes(Decl *New, Decl *Old) { + Attr *attr = const_cast(Old->getAttrs()), *tmp; + +// FIXME: fix this code to cleanup the Old attrs correctly + while (attr) { + tmp = attr; + attr = attr->getNext(); + + if (!DeclHasAttr(New, tmp)) { + New->addAttr(tmp); + } else { + tmp->setNext(0); + delete(tmp); + } + } +} + /// MergeFunctionDecl - We just parsed a function 'New' which has the same name /// and scope as a previous declaration 'Old'. Figure out how to resolve this /// situation, merging decls or emitting diagnostics as appropriate. @@ -256,7 +283,8 @@ return New; } - // FIXME: propagate old Attrs to the New decl + MergeAttributes(New, Old); + QualType OldQType = Old->getCanonicalType(); QualType NewQType = New->getCanonicalType(); @@ -326,6 +354,9 @@ Diag(OldD->getLocation(), diag::err_previous_definition); return New; } + + MergeAttributes(New, Old); + // Verify the types match. if (Old->getCanonicalType() != New->getCanonicalType() && !areEquivalentArrayTypes(New->getCanonicalType(), Old->getCanonicalType())) { @@ -1781,8 +1812,23 @@ } break; case AttributeList::AT_deprecated: - New->addAttr(new DeprecatedAttr()); + 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_aligned: HandleAlignedAttribute(New, Attr); break; @@ -1795,6 +1841,9 @@ case AttributeList::AT_noreturn: HandleNoReturnAttribute(New, Attr); break; + case AttributeList::AT_format: + HandleFormatAttribute(New, Attr); + break; default: #if 0 // TODO: when we have the full set of attributes, warn about unknown ones. @@ -1952,6 +2001,177 @@ d->addAttr(new NoReturnAttr()); } +void Sema::HandleDeprecatedAttribute(Decl *d, 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, AttributeList *rawAttr) { + // check the attribute arguments. + if (rawAttr->getNumArgs() != 0) { + Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, + std::string("1")); + return; + } + + if (!rawAttr->getParameterName()) { + Diag(rawAttr->getLoc(), diag::err_attribute_argument_n_not_string, + "visibility", std::string("1")); + return; + } + + const char *typeStr = rawAttr->getParameterName()->getName(); + llvm::GlobalValue::VisibilityTypes type; + + if (!memcmp(typeStr, "default", 7)) + type = llvm::GlobalValue::DefaultVisibility; + else if (!memcmp(typeStr, "hidden", 6)) + type = llvm::GlobalValue::HiddenVisibility; + else if (!memcmp(typeStr, "internal", 8)) + type = llvm::GlobalValue::HiddenVisibility; // FIXME + else if (!memcmp(typeStr, "protected", 9)) + type = llvm::GlobalValue::ProtectedVisibility; + else { + Diag(rawAttr->getLoc(), diag::warn_attribute_type_not_supported, + "visibility", typeStr); + return; + } + + d->addAttr(new VisibilityAttr(type)); +} + +void Sema::HandleWeakAttribute(Decl *d, 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, 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, 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::HandleNothrowAttribute(Decl *d, 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()); +} + +void Sema::HandleFormatAttribute(Decl *d, 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; + } + + FunctionDecl *Fn = dyn_cast(d); + if (!Fn) { + Diag(rawAttr->getLoc(), diag::warn_attribute_wrong_decl_type, + "format", "function"); + return; + } + + // FIXME: in C++ the implicit 'this' function parameter also counts. + // the index must start in 1 and the limit is numargs+1 + unsigned NumArgs = Fn->getNumParams()+1; // +1 for ... + + 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; + } + + if (!((FormatLen == 5 && !memcmp(Format, "scanf", 5)) + || (FormatLen == 6 && !memcmp(Format, "printf", 6)) + || (FormatLen == 7 && !memcmp(Format, "strfmon", 7)) + || (FormatLen == 8 && !memcmp(Format, "strftime", 8)))) { + Diag(rawAttr->getLoc(), diag::warn_attribute_type_not_supported, + "format", rawAttr->getParameterName()->getName()); + return; + } + + Expr *IdxExpr = static_cast(rawAttr->getArg(0)); + llvm::APSInt Idx(32); + 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() < 1 || Idx.getZExtValue() > NumArgs) { + Diag(rawAttr->getLoc(), diag::err_attribute_argument_out_of_bounds, + "format", std::string("2"), IdxExpr->getSourceRange()); + return; + } + + Expr *FirstArgExpr = static_cast(rawAttr->getArg(1)); + llvm::APSInt FirstArg(32); + if (!FirstArgExpr->isIntegerConstantExpr(FirstArg, Context)) { + Diag(rawAttr->getLoc(), diag::err_attribute_argument_n_not_int, + "format", std::string("3"), FirstArgExpr->getSourceRange()); + return; + } + + if (FormatLen == 8 && !memcmp(Format, "strftime", 8)) { + if (FirstArg.getZExtValue() != 0) { + Diag(rawAttr->getLoc(), diag::err_format_strftime_third_parameter, + FirstArgExpr->getSourceRange()); + return; + } + } else if (FirstArg.getZExtValue() > 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::HandleAnnotateAttribute(Decl *d, AttributeList *rawAttr) { // check the attribute arguments. if (rawAttr->getNumArgs() != 1) { Index: CodeGen/CodeGenModule.cpp =================================================================== --- CodeGen/CodeGenModule.cpp (revision 47826) +++ CodeGen/CodeGenModule.cpp (working copy) @@ -242,25 +242,38 @@ assert(GV->getType()->getElementType() == Init->getType() && "Initializer codegen type mismatch!"); GV->setInitializer(Init); + + if (const VisibilityAttr *attr = D->getAttr()) + GV->setVisibility(attr->getVisibility()); + // FIXME: else handle -fvisibility // Set the llvm linkage type as appropriate. - // FIXME: This isn't right. This should handle common linkage and other - // stuff. - switch (D->getStorageClass()) { - case VarDecl::Auto: - case VarDecl::Register: - assert(0 && "Can't have auto or register globals"); - case VarDecl::None: - if (!D->getInit()) - GV->setLinkage(llvm::GlobalVariable::WeakLinkage); - break; - case VarDecl::Extern: - case VarDecl::PrivateExtern: - // todo: common - break; - case VarDecl::Static: - GV->setLinkage(llvm::GlobalVariable::InternalLinkage); - break; + if (D->getAttr()) + GV->setLinkage(llvm::Function::DLLImportLinkage); + else if (D->getAttr()) + GV->setLinkage(llvm::Function::DLLExportLinkage); + else if (D->getAttr()) { + GV->setLinkage(llvm::GlobalVariable::WeakLinkage); + + } else { + // FIXME: This isn't right. This should handle common linkage and other + // stuff. + switch (D->getStorageClass()) { + case VarDecl::Auto: + case VarDecl::Register: + assert(0 && "Can't have auto or register globals"); + case VarDecl::None: + if (!D->getInit()) + GV->setLinkage(llvm::GlobalVariable::WeakLinkage); + break; + case VarDecl::Extern: + case VarDecl::PrivateExtern: + // todo: common + break; + case VarDecl::Static: + GV->setLinkage(llvm::GlobalVariable::InternalLinkage); + break; + } } } Index: CodeGen/CodeGenFunction.cpp =================================================================== --- CodeGen/CodeGenFunction.cpp (revision 47826) +++ CodeGen/CodeGenFunction.cpp (working copy) @@ -18,6 +18,7 @@ #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" #include "llvm/Function.h" +#include "llvm/ParamAttrsList.h" #include "llvm/Analysis/Verifier.h" #include "llvm/Support/CFG.h" using namespace clang; @@ -67,11 +68,33 @@ // TODO: Set up linkage and many other things. Note, this is a simple // approximation of what we really want. - if (FD->getStorageClass() == FunctionDecl::Static) + if (FD->getAttr()) + CurFn->setLinkage(llvm::Function::DLLImportLinkage); + else if (FD->getAttr()) + CurFn->setLinkage(llvm::Function::DLLExportLinkage); + else if (FD->getAttr() || FD->isInline()) + CurFn->setLinkage(llvm::Function::WeakLinkage); + else if (FD->getStorageClass() == FunctionDecl::Static) CurFn->setLinkage(llvm::Function::InternalLinkage); - else if (FD->isInline()) - CurFn->setLinkage(llvm::Function::WeakLinkage); - + + if (const VisibilityAttr *attr = FD->getAttr()) + CurFn->setVisibility(attr->getVisibility()); + // FIXME: else handle -fvisibility + + + llvm::ParamAttrsVector ParamAttrsVec; + + if (FD->getAttr()) + ParamAttrsVec.push_back( + llvm::ParamAttrsWithIndex::get(ParamAttrsVec.size(), llvm::ParamAttr::NoUnwind)); + if (FD->getAttr()) + ParamAttrsVec.push_back( + llvm::ParamAttrsWithIndex::get(ParamAttrsVec.size(), llvm::ParamAttr::NoReturn)); + + if (!ParamAttrsVec.empty()) + CurFn->setParamAttrs(llvm::ParamAttrsList::get(ParamAttrsVec)); + + llvm::BasicBlock *EntryBB = new llvm::BasicBlock("entry", CurFn); // Create a marker to make it easy to insert allocas into the entryblock Index: Parse/AttributeList.cpp =================================================================== --- Parse/AttributeList.cpp (revision 47826) +++ Parse/AttributeList.cpp (working copy) @@ -51,18 +51,33 @@ } switch (Len) { - case 6: + case 4: + if (!memcmp(Str, "weak", 4)) return AT_weak; + if (!memcmp(Str, "pure", 4)) return AT_pure; + break; + case 6: if (!memcmp(Str, "packed", 6)) return AT_packed; + if (!memcmp(Str, "malloc", 6)) return AT_malloc; + if (!memcmp(Str, "format", 6)) return AT_format; + if (!memcmp(Str, "unused", 6)) return AT_unused; break; case 7: if (!memcmp(Str, "aligned", 7)) return AT_aligned; + if (!memcmp(Str, "nothrow", 7)) return AT_nothrow; + if (!memcmp(Str, "nonnull", 7)) return AT_nonnull; break; case 8: if (!memcmp(Str, "annotate", 8)) return AT_annotate; if (!memcmp(Str, "noreturn", 8)) return AT_noreturn; + if (!memcmp(Str, "noinline", 8)) return AT_noinline; break; + case 9: + if (!memcmp(Str, "dllimport", 9)) return AT_dllimport; + if (!memcmp(Str, "dllexport", 9)) return AT_dllexport; + break; case 10: if (!memcmp(Str, "deprecated", 10)) return AT_deprecated; + if (!memcmp(Str, "visibility", 10)) return AT_visibility; break; case 11: if (!memcmp(Str, "vector_size", 11)) return AT_vector_size; @@ -73,6 +88,9 @@ case 15: if (!memcmp(Str, "ocu_vector_type", 15)) return AT_ocu_vector_type; break; - } + case 18: + if (!memcmp(Str, "warn_unused_result", 18)) return AT_warn_unused_result; + break; + } return UnknownAttribute; }