diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp | 3054 |
1 files changed, 1366 insertions, 1688 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp index 3e58386..61683cd 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp @@ -12,13 +12,13 @@ //===----------------------------------------------------------------------===// #include "clang/Sema/SemaInternal.h" -#include "TargetAttributesSema.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/Mangle.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/SourceManager.h" @@ -32,86 +32,23 @@ using namespace clang; using namespace sema; -/// These constants match the enumerated choices of -/// warn_attribute_wrong_decl_type and err_attribute_wrong_decl_type. -enum AttributeDeclKind { - ExpectedFunction, - ExpectedUnion, - ExpectedVariableOrFunction, - ExpectedFunctionOrMethod, - ExpectedParameter, - ExpectedFunctionMethodOrBlock, - ExpectedFunctionMethodOrClass, - ExpectedFunctionMethodOrParameter, - ExpectedClass, - ExpectedVariable, - ExpectedMethod, - ExpectedVariableFunctionOrLabel, - ExpectedFieldOrGlobalVar, - ExpectedStruct, - ExpectedVariableFunctionOrTag, - ExpectedTLSVar, - ExpectedVariableOrField, - ExpectedVariableFieldOrTag, - ExpectedTypeOrNamespace, - ExpectedObjectiveCInterface, - ExpectedMethodOrProperty, - ExpectedStructOrUnion, - ExpectedStructOrUnionOrClass -}; +namespace AttributeLangSupport { + enum LANG { + C, + Cpp, + ObjC + }; +} //===----------------------------------------------------------------------===// // Helper functions //===----------------------------------------------------------------------===// -static const FunctionType *getFunctionType(const Decl *D, - bool blocksToo = true) { - QualType Ty; - if (const ValueDecl *decl = dyn_cast<ValueDecl>(D)) - Ty = decl->getType(); - else if (const FieldDecl *decl = dyn_cast<FieldDecl>(D)) - Ty = decl->getType(); - else if (const TypedefNameDecl* decl = dyn_cast<TypedefNameDecl>(D)) - Ty = decl->getUnderlyingType(); - else - return 0; - - if (Ty->isFunctionPointerType()) - Ty = Ty->getAs<PointerType>()->getPointeeType(); - else if (blocksToo && Ty->isBlockPointerType()) - Ty = Ty->getAs<BlockPointerType>()->getPointeeType(); - - return Ty->getAs<FunctionType>(); -} - -// FIXME: We should provide an abstraction around a method or function -// to provide the following bits of information. - -/// isFunction - 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(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(const Decl *D) { - if (isFunctionOrMethod(D)) - return true; - // check for block is more involved. - if (const VarDecl *V = dyn_cast<VarDecl>(D)) { - QualType Ty = V->getType(); - return Ty->isBlockPointerType(); - } - return isa<BlockDecl>(D); + return (D->getFunctionType() != nullptr) || isa<ObjCMethodDecl>(D); } /// Return true if the given decl has a declarator that should have @@ -126,42 +63,39 @@ static bool hasDeclarator(const Decl *D) { /// information. This decl should have already passed /// isFunctionOrMethod or isFunctionOrMethodOrBlock. static bool hasFunctionProto(const Decl *D) { - if (const FunctionType *FnTy = getFunctionType(D)) + if (const FunctionType *FnTy = D->getFunctionType()) return isa<FunctionProtoType>(FnTy); - else { - assert(isa<ObjCMethodDecl>(D) || isa<BlockDecl>(D)); - return true; - } + return isa<ObjCMethodDecl>(D) || isa<BlockDecl>(D); } -/// getFunctionOrMethodNumArgs - Return number of function or method -/// arguments. It is an error to call this on a K&R function (use +/// getFunctionOrMethodNumParams - Return number of function or method +/// parameters. It is an error to call this on a K&R function (use /// hasFunctionProto first). -static unsigned getFunctionOrMethodNumArgs(const Decl *D) { - if (const FunctionType *FnTy = getFunctionType(D)) - return cast<FunctionProtoType>(FnTy)->getNumArgs(); +static unsigned getFunctionOrMethodNumParams(const Decl *D) { + if (const FunctionType *FnTy = D->getFunctionType()) + return cast<FunctionProtoType>(FnTy)->getNumParams(); if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) return BD->getNumParams(); return cast<ObjCMethodDecl>(D)->param_size(); } -static QualType getFunctionOrMethodArgType(const Decl *D, unsigned Idx) { - if (const FunctionType *FnTy = getFunctionType(D)) - return cast<FunctionProtoType>(FnTy)->getArgType(Idx); +static QualType getFunctionOrMethodParamType(const Decl *D, unsigned Idx) { + if (const FunctionType *FnTy = D->getFunctionType()) + return cast<FunctionProtoType>(FnTy)->getParamType(Idx); if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) return BD->getParamDecl(Idx)->getType(); - return cast<ObjCMethodDecl>(D)->param_begin()[Idx]->getType(); + return cast<ObjCMethodDecl>(D)->parameters()[Idx]->getType(); } static QualType getFunctionOrMethodResultType(const Decl *D) { - if (const FunctionType *FnTy = getFunctionType(D)) - return cast<FunctionProtoType>(FnTy)->getResultType(); - return cast<ObjCMethodDecl>(D)->getResultType(); + if (const FunctionType *FnTy = D->getFunctionType()) + return cast<FunctionType>(FnTy)->getReturnType(); + return cast<ObjCMethodDecl>(D)->getReturnType(); } static bool isFunctionOrMethodVariadic(const Decl *D) { - if (const FunctionType *FnTy = getFunctionType(D)) { + if (const FunctionType *FnTy = D->getFunctionType()) { const FunctionProtoType *proto = cast<FunctionProtoType>(FnTy); return proto->isVariadic(); } else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) @@ -227,30 +161,63 @@ static bool checkAttributeNumArgs(Sema &S, const AttributeList &Attr, return true; } - /// \brief Check if the attribute has at least as many args as Num. May /// output an error. static bool checkAttributeAtLeastNumArgs(Sema &S, const AttributeList &Attr, unsigned Num) { if (getNumAttributeArgs(Attr) < Num) { - S.Diag(Attr.getLoc(), diag::err_attribute_too_few_arguments) << Num; + S.Diag(Attr.getLoc(), diag::err_attribute_too_few_arguments) + << Attr.getName() << Num; return false; } return true; } -/// \brief Check if IdxExpr is a valid argument index for a function or +/// \brief If Expr is a valid integer constant, get the value of the integer +/// expression and return success or failure. May output an error. +static bool checkUInt32Argument(Sema &S, const AttributeList &Attr, + const Expr *Expr, uint32_t &Val, + unsigned Idx = UINT_MAX) { + llvm::APSInt I(32); + if (Expr->isTypeDependent() || Expr->isValueDependent() || + !Expr->isIntegerConstantExpr(I, S.Context)) { + if (Idx != UINT_MAX) + S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) + << Attr.getName() << Idx << AANT_ArgumentIntegerConstant + << Expr->getSourceRange(); + else + S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) + << Attr.getName() << AANT_ArgumentIntegerConstant + << Expr->getSourceRange(); + return false; + } + Val = (uint32_t)I.getZExtValue(); + return true; +} + +/// \brief Diagnose mutually exclusive attributes when present on a given +/// declaration. Returns true if diagnosed. +template <typename AttrTy> +static bool checkAttrMutualExclusion(Sema &S, Decl *D, + const AttributeList &Attr) { + if (AttrTy *A = D->getAttr<AttrTy>()) { + S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible) + << Attr.getName() << A; + return true; + } + return false; +} + +/// \brief Check if IdxExpr is a valid parameter index for a function or /// instance method D. May output an error. /// /// \returns true if IdxExpr is a valid index. -static bool checkFunctionOrMethodArgumentIndex(Sema &S, const Decl *D, - StringRef AttrName, - SourceLocation AttrLoc, - unsigned AttrArgNum, - const Expr *IdxExpr, - uint64_t &Idx) -{ +static bool checkFunctionOrMethodParameterIndex(Sema &S, const Decl *D, + const AttributeList &Attr, + unsigned AttrArgNum, + const Expr *IdxExpr, + uint64_t &Idx) { assert(isFunctionOrMethod(D)); // In C++ the implicit 'this' function parameter also counts. @@ -258,30 +225,30 @@ static bool checkFunctionOrMethodArgumentIndex(Sema &S, const Decl *D, bool HP = hasFunctionProto(D); bool HasImplicitThisParam = isInstanceMethod(D); bool IV = HP && isFunctionOrMethodVariadic(D); - unsigned NumArgs = (HP ? getFunctionOrMethodNumArgs(D) : 0) + - HasImplicitThisParam; + unsigned NumParams = + (HP ? getFunctionOrMethodNumParams(D) : 0) + HasImplicitThisParam; llvm::APSInt IdxInt; if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() || !IdxExpr->isIntegerConstantExpr(IdxInt, S.Context)) { - std::string Name = std::string("'") + AttrName.str() + std::string("'"); - S.Diag(AttrLoc, diag::err_attribute_argument_n_type) << Name.c_str() - << AttrArgNum << AANT_ArgumentIntegerConstant << IdxExpr->getSourceRange(); + S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) + << Attr.getName() << AttrArgNum << AANT_ArgumentIntegerConstant + << IdxExpr->getSourceRange(); return false; } Idx = IdxInt.getLimitedValue(); - if (Idx < 1 || (!IV && Idx > NumArgs)) { - S.Diag(AttrLoc, diag::err_attribute_argument_out_of_bounds) - << AttrName << AttrArgNum << IdxExpr->getSourceRange(); + if (Idx < 1 || (!IV && Idx > NumParams)) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds) + << Attr.getName() << AttrArgNum << IdxExpr->getSourceRange(); return false; } Idx--; // Convert to zero-based. if (HasImplicitThisParam) { if (Idx == 0) { - S.Diag(AttrLoc, + S.Diag(Attr.getLoc(), diag::err_attribute_invalid_implicit_this_argument) - << AttrName << IdxExpr->getSourceRange(); + << Attr.getName() << IdxExpr->getSourceRange(); return false; } --Idx; @@ -326,17 +293,13 @@ bool Sema::checkStringLiteralArgumentAttr(const AttributeList &Attr, return true; } -/// -/// \brief Check if passed in Decl is a field or potentially shared global var -/// \return true if the Decl is a field or potentially shared global variable -/// -static bool mayBeSharedVariable(const Decl *D) { - if (isa<FieldDecl>(D)) - return true; - if (const VarDecl *vd = dyn_cast<VarDecl>(D)) - return vd->hasGlobalStorage() && !vd->getTLSKind(); - - return false; +/// \brief Applies the given attribute to the Decl without performing any +/// additional semantic checking. +template <typename AttrType> +static void handleSimpleAttribute(Sema &S, Decl *D, + const AttributeList &Attr) { + D->addAttr(::new (S.Context) AttrType(Attr.getRange(), S.Context, + Attr.getAttributeSpellingListIndex())); } /// \brief Check if the passed-in expression is of type int or bool. @@ -367,28 +330,24 @@ static bool threadSafetyCheckIsSmartPointer(Sema &S, const RecordType* RT) { /// \return true if the Decl is a pointer type; false otherwise static bool threadSafetyCheckIsPointer(Sema &S, const Decl *D, const AttributeList &Attr) { - if (const ValueDecl *vd = dyn_cast<ValueDecl>(D)) { - QualType QT = vd->getType(); - if (QT->isAnyPointerType()) - return true; - - if (const RecordType *RT = QT->getAs<RecordType>()) { - // If it's an incomplete type, it could be a smart pointer; skip it. - // (We don't want to force template instantiation if we can avoid it, - // since that would alter the order in which templates are instantiated.) - if (RT->isIncompleteType()) - return true; + const ValueDecl *vd = cast<ValueDecl>(D); + QualType QT = vd->getType(); + if (QT->isAnyPointerType()) + return true; - if (threadSafetyCheckIsSmartPointer(S, RT)) - return true; - } + if (const RecordType *RT = QT->getAs<RecordType>()) { + // If it's an incomplete type, it could be a smart pointer; skip it. + // (We don't want to force template instantiation if we can avoid it, + // since that would alter the order in which templates are instantiated.) + if (RT->isIncompleteType()) + return true; - S.Diag(Attr.getLoc(), diag::warn_thread_attribute_decl_not_pointer) - << Attr.getName()->getName() << QT; - } else { - S.Diag(Attr.getLoc(), diag::err_attribute_can_be_applied_only_to_value_decl) - << Attr.getName(); + if (threadSafetyCheckIsSmartPointer(S, RT)) + return true; } + + S.Diag(Attr.getLoc(), diag::warn_thread_attribute_decl_not_pointer) + << Attr.getName() << QT; return false; } @@ -402,68 +361,101 @@ static const RecordType *getRecordType(QualType QT) { if (const PointerType *PT = QT->getAs<PointerType>()) return PT->getPointeeType()->getAs<RecordType>(); - return 0; -} - - -static bool checkBaseClassIsLockableCallback(const CXXBaseSpecifier *Specifier, - CXXBasePath &Path, void *Unused) { - const RecordType *RT = Specifier->getType()->getAs<RecordType>(); - if (RT->getDecl()->getAttr<LockableAttr>()) - return true; - return false; + return nullptr; } - -/// \brief Thread Safety Analysis: Checks that the passed in RecordType -/// resolves to a lockable object. -static void checkForLockableRecord(Sema &S, Decl *D, const AttributeList &Attr, - QualType Ty) { +static bool checkRecordTypeForCapability(Sema &S, QualType Ty) { const RecordType *RT = getRecordType(Ty); - // Warn if could not get record type for this argument. - if (!RT) { - S.Diag(Attr.getLoc(), diag::warn_thread_attribute_argument_not_class) - << Attr.getName() << Ty.getAsString(); - return; - } + if (!RT) + return false; - // Don't check for lockable if the class hasn't been defined yet. + // Don't check for the capability if the class hasn't been defined yet. if (RT->isIncompleteType()) - return; + return true; - // Allow smart pointers to be used as lockable objects. + // Allow smart pointers to be used as capability objects. // FIXME -- Check the type that the smart pointer points to. if (threadSafetyCheckIsSmartPointer(S, RT)) - return; + return true; - // Check if the type is lockable. + // Check if the record itself has a capability. RecordDecl *RD = RT->getDecl(); - if (RD->getAttr<LockableAttr>()) - return; + if (RD->hasAttr<CapabilityAttr>()) + return true; - // Else check if any base classes are lockable. + // Else check if any base classes have a capability. if (CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) { CXXBasePaths BPaths(false, false); - if (CRD->lookupInBases(checkBaseClassIsLockableCallback, 0, BPaths)) - return; + if (CRD->lookupInBases([](const CXXBaseSpecifier *BS, CXXBasePath &P, + void *) { + return BS->getType()->getAs<RecordType>() + ->getDecl()->hasAttr<CapabilityAttr>(); + }, nullptr, BPaths)) + return true; + } + return false; +} + +static bool checkTypedefTypeForCapability(QualType Ty) { + const auto *TD = Ty->getAs<TypedefType>(); + if (!TD) + return false; + + TypedefNameDecl *TN = TD->getDecl(); + if (!TN) + return false; + + return TN->hasAttr<CapabilityAttr>(); +} + +static bool typeHasCapability(Sema &S, QualType Ty) { + if (checkTypedefTypeForCapability(Ty)) + return true; + + if (checkRecordTypeForCapability(S, Ty)) + return true; + + return false; +} + +static bool isCapabilityExpr(Sema &S, const Expr *Ex) { + // Capability expressions are simple expressions involving the boolean logic + // operators &&, || or !, a simple DeclRefExpr, CastExpr or a ParenExpr. Once + // a DeclRefExpr is found, its type should be checked to determine whether it + // is a capability or not. + + if (const auto *E = dyn_cast<DeclRefExpr>(Ex)) + return typeHasCapability(S, E->getType()); + else if (const auto *E = dyn_cast<CastExpr>(Ex)) + return isCapabilityExpr(S, E->getSubExpr()); + else if (const auto *E = dyn_cast<ParenExpr>(Ex)) + return isCapabilityExpr(S, E->getSubExpr()); + else if (const auto *E = dyn_cast<UnaryOperator>(Ex)) { + if (E->getOpcode() == UO_LNot) + return isCapabilityExpr(S, E->getSubExpr()); + return false; + } else if (const auto *E = dyn_cast<BinaryOperator>(Ex)) { + if (E->getOpcode() == BO_LAnd || E->getOpcode() == BO_LOr) + return isCapabilityExpr(S, E->getLHS()) && + isCapabilityExpr(S, E->getRHS()); + return false; } - S.Diag(Attr.getLoc(), diag::warn_thread_attribute_argument_not_lockable) - << Attr.getName() << Ty.getAsString(); + return false; } -/// \brief Thread Safety Analysis: Checks that all attribute arguments, starting -/// from Sidx, resolve to a lockable object. +/// \brief Checks that all attribute arguments, starting from Sidx, resolve to +/// a capability object. /// \param Sidx The attribute argument index to start checking with. /// \param ParamIdxOk Whether an argument can be indexing into a function /// parameter list. -static void checkAttrArgsAreLockableObjs(Sema &S, Decl *D, - const AttributeList &Attr, - SmallVectorImpl<Expr*> &Args, - int Sidx = 0, - bool ParamIdxOk = false) { - for(unsigned Idx = Sidx; Idx < Attr.getNumArgs(); ++Idx) { +static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, + const AttributeList &Attr, + SmallVectorImpl<Expr *> &Args, + int Sidx = 0, + bool ParamIdxOk = false) { + for (unsigned Idx = Sidx; Idx < Attr.getNumArgs(); ++Idx) { Expr *ArgExp = Attr.getArgAsExpr(Idx); if (ArgExp->isTypeDependent()) { @@ -499,7 +491,7 @@ static void checkAttrArgsAreLockableObjs(Sema &S, Decl *D, if (DRE->getDecl()->isCXXInstanceMember()) ArgTy = DRE->getDecl()->getType(); - // First see if we can just cast to record type, or point to record type. + // First see if we can just cast to record type, or pointer to record type. const RecordType *RT = getRecordType(ArgTy); // Now check if we index into a record type function param. @@ -520,7 +512,13 @@ static void checkAttrArgsAreLockableObjs(Sema &S, Decl *D, } } - checkForLockableRecord(S, D, Attr, ArgTy); + // If the type does not have a capability, see if the components of the + // expression have capabilities. This allows for writing C code where the + // capability may be on the type, and the expression is a capability + // boolean logic expression. Eg) requires_capability(A || B && !C) + if (!typeHasCapability(S, ArgTy) && !isCapabilityExpr(S, ArgExp)) + S.Diag(Attr.getLoc(), diag::warn_thread_attribute_argument_not_lockable) + << Attr.getName() << ArgTy; Args.push_back(ArgExp); } @@ -534,38 +532,8 @@ static void checkAttrArgsAreLockableObjs(Sema &S, Decl *D, // least add some helper functions to check most argument patterns (# // and types of args). -enum ThreadAttributeDeclKind { - ThreadExpectedFieldOrGlobalVar, - ThreadExpectedFunctionOrMethod, - ThreadExpectedClassOrStruct -}; - -static bool checkGuardedVarAttrCommon(Sema &S, Decl *D, - const AttributeList &Attr) { - // D must be either a member field or global (potentially shared) variable. - if (!mayBeSharedVariable(D)) { - S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type) - << Attr.getName() << ThreadExpectedFieldOrGlobalVar; - return false; - } - - return true; -} - -static void handleGuardedVarAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkGuardedVarAttrCommon(S, D, Attr)) - return; - - D->addAttr(::new (S.Context) - GuardedVarAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); -} - static void handlePtGuardedVarAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkGuardedVarAttrCommon(S, D, Attr)) - return; - if (!threadSafetyCheckIsPointer(S, D, Attr)) return; @@ -577,16 +545,9 @@ static void handlePtGuardedVarAttr(Sema &S, Decl *D, static bool checkGuardedByAttrCommon(Sema &S, Decl *D, const AttributeList &Attr, Expr* &Arg) { - // D must be either a member field or global (potentially shared) variable. - if (!mayBeSharedVariable(D)) { - S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type) - << Attr.getName() << ThreadExpectedFieldOrGlobalVar; - return false; - } - SmallVector<Expr*, 1> Args; // check that all arguments are lockable objects - checkAttrArgsAreLockableObjs(S, D, Attr, Args); + checkAttrArgsAreCapabilityObjs(S, D, Attr, Args); unsigned Size = Args.size(); if (Size != 1) return false; @@ -597,16 +558,17 @@ static bool checkGuardedByAttrCommon(Sema &S, Decl *D, } static void handleGuardedByAttr(Sema &S, Decl *D, const AttributeList &Attr) { - Expr *Arg = 0; + Expr *Arg = nullptr; if (!checkGuardedByAttrCommon(S, D, Attr, Arg)) return; - D->addAttr(::new (S.Context) GuardedByAttr(Attr.getRange(), S.Context, Arg)); + D->addAttr(::new (S.Context) GuardedByAttr(Attr.getRange(), S.Context, Arg, + Attr.getAttributeSpellingListIndex())); } static void handlePtGuardedByAttr(Sema &S, Decl *D, const AttributeList &Attr) { - Expr *Arg = 0; + Expr *Arg = nullptr; if (!checkGuardedByAttrCommon(S, D, Attr, Arg)) return; @@ -614,85 +576,8 @@ static void handlePtGuardedByAttr(Sema &S, Decl *D, return; D->addAttr(::new (S.Context) PtGuardedByAttr(Attr.getRange(), - S.Context, Arg)); -} - -static bool checkLockableAttrCommon(Sema &S, Decl *D, - const AttributeList &Attr) { - // FIXME: Lockable structs for C code. - if (!isa<RecordDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type) - << Attr.getName() << ThreadExpectedClassOrStruct; - return false; - } - - return true; -} - -static void handleLockableAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkLockableAttrCommon(S, D, Attr)) - return; - - D->addAttr(::new (S.Context) LockableAttr(Attr.getRange(), S.Context)); -} - -static void handleScopedLockableAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!checkLockableAttrCommon(S, D, Attr)) - return; - - D->addAttr(::new (S.Context) - ScopedLockableAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); -} - -static void handleNoThreadSafetyAnalysis(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type) - << Attr.getName() << ThreadExpectedFunctionOrMethod; - return; - } - - D->addAttr(::new (S.Context) NoThreadSafetyAnalysisAttr(Attr.getRange(), - S.Context)); -} - -static void handleNoSanitizeAddressAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunctionOrMethod; - return; - } - - D->addAttr(::new (S.Context) - NoSanitizeAddressAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); -} - -static void handleNoSanitizeMemory(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunctionOrMethod; - return; - } - - D->addAttr(::new (S.Context) NoSanitizeMemoryAttr(Attr.getRange(), - S.Context)); -} - -static void handleNoSanitizeThread(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunctionOrMethod; - return; - } - - D->addAttr(::new (S.Context) NoSanitizeThreadAttr(Attr.getRange(), - S.Context)); + S.Context, Arg, + Attr.getAttributeSpellingListIndex())); } static bool checkAcquireOrderAttrCommon(Sema &S, Decl *D, @@ -701,19 +586,11 @@ static bool checkAcquireOrderAttrCommon(Sema &S, Decl *D, if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) return false; - // D must be either a member field or global (potentially shared) variable. - ValueDecl *VD = dyn_cast<ValueDecl>(D); - if (!VD || !mayBeSharedVariable(D)) { - S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type) - << Attr.getName() << ThreadExpectedFieldOrGlobalVar; - return false; - } - // Check that this attribute only applies to lockable types. - QualType QT = VD->getType(); + QualType QT = cast<ValueDecl>(D)->getType(); if (!QT->isDependentType()) { const RecordType *RT = getRecordType(QT); - if (!RT || !RT->getDecl()->getAttr<LockableAttr>()) { + if (!RT || !RT->getDecl()->hasAttr<CapabilityAttr>()) { S.Diag(Attr.getLoc(), diag::warn_thread_attribute_decl_not_lockable) << Attr.getName(); return false; @@ -721,7 +598,7 @@ static bool checkAcquireOrderAttrCommon(Sema &S, Decl *D, } // Check that all arguments are lockable objects. - checkAttrArgsAreLockableObjs(S, D, Attr, Args); + checkAttrArgsAreCapabilityObjs(S, D, Attr, Args); if (Args.empty()) return false; @@ -758,47 +635,12 @@ static bool checkLockFunAttrCommon(Sema &S, Decl *D, const AttributeList &Attr, SmallVectorImpl<Expr *> &Args) { // zero or more arguments ok - - // check that the attribute is applied to a function - if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type) - << Attr.getName() << ThreadExpectedFunctionOrMethod; - return false; - } - // check that all arguments are lockable objects - checkAttrArgsAreLockableObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true); + checkAttrArgsAreCapabilityObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true); return true; } -static void handleSharedLockFunctionAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - SmallVector<Expr*, 1> Args; - if (!checkLockFunAttrCommon(S, D, Attr, Args)) - return; - - unsigned Size = Args.size(); - Expr **StartArg = Size == 0 ? 0 : &Args[0]; - D->addAttr(::new (S.Context) - SharedLockFunctionAttr(Attr.getRange(), S.Context, StartArg, Size, - Attr.getAttributeSpellingListIndex())); -} - -static void handleExclusiveLockFunctionAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - SmallVector<Expr*, 1> Args; - if (!checkLockFunAttrCommon(S, D, Attr, Args)) - return; - - unsigned Size = Args.size(); - Expr **StartArg = Size == 0 ? 0 : &Args[0]; - D->addAttr(::new (S.Context) - ExclusiveLockFunctionAttr(Attr.getRange(), S.Context, - StartArg, Size, - Attr.getAttributeSpellingListIndex())); -} - static void handleAssertSharedLockAttr(Sema &S, Decl *D, const AttributeList &Attr) { SmallVector<Expr*, 1> Args; @@ -806,7 +648,7 @@ static void handleAssertSharedLockAttr(Sema &S, Decl *D, return; unsigned Size = Args.size(); - Expr **StartArg = Size == 0 ? 0 : &Args[0]; + Expr **StartArg = Size == 0 ? nullptr : &Args[0]; D->addAttr(::new (S.Context) AssertSharedLockAttr(Attr.getRange(), S.Context, StartArg, Size, Attr.getAttributeSpellingListIndex())); @@ -819,7 +661,7 @@ static void handleAssertExclusiveLockAttr(Sema &S, Decl *D, return; unsigned Size = Args.size(); - Expr **StartArg = Size == 0 ? 0 : &Args[0]; + Expr **StartArg = Size == 0 ? nullptr : &Args[0]; D->addAttr(::new (S.Context) AssertExclusiveLockAttr(Attr.getRange(), S.Context, StartArg, Size, @@ -833,12 +675,6 @@ static bool checkTryLockFunAttrCommon(Sema &S, Decl *D, if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) return false; - if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type) - << Attr.getName() << ThreadExpectedFunctionOrMethod; - return false; - } - if (!isIntOrBool(Attr.getArgAsExpr(0))) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) << Attr.getName() << 1 << AANT_ArgumentIntOrBool; @@ -846,7 +682,7 @@ static bool checkTryLockFunAttrCommon(Sema &S, Decl *D, } // check that all arguments are lockable objects - checkAttrArgsAreLockableObjs(S, D, Attr, Args, 1); + checkAttrArgsAreCapabilityObjs(S, D, Attr, Args, 1); return true; } @@ -877,84 +713,11 @@ static void handleExclusiveTrylockFunctionAttr(Sema &S, Decl *D, Attr.getAttributeSpellingListIndex())); } -static bool checkLocksRequiredCommon(Sema &S, Decl *D, - const AttributeList &Attr, - SmallVectorImpl<Expr *> &Args) { - if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) - return false; - - if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type) - << Attr.getName() << ThreadExpectedFunctionOrMethod; - return false; - } - - // check that all arguments are lockable objects - checkAttrArgsAreLockableObjs(S, D, Attr, Args); - if (Args.empty()) - return false; - - return true; -} - -static void handleExclusiveLocksRequiredAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - SmallVector<Expr*, 1> Args; - if (!checkLocksRequiredCommon(S, D, Attr, Args)) - return; - - Expr **StartArg = &Args[0]; - D->addAttr(::new (S.Context) - ExclusiveLocksRequiredAttr(Attr.getRange(), S.Context, - StartArg, Args.size(), - Attr.getAttributeSpellingListIndex())); -} - -static void handleSharedLocksRequiredAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - SmallVector<Expr*, 1> Args; - if (!checkLocksRequiredCommon(S, D, Attr, Args)) - return; - - Expr **StartArg = &Args[0]; - D->addAttr(::new (S.Context) - SharedLocksRequiredAttr(Attr.getRange(), S.Context, - StartArg, Args.size(), - Attr.getAttributeSpellingListIndex())); -} - -static void handleUnlockFunAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - // zero or more arguments ok - - if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type) - << Attr.getName() << ThreadExpectedFunctionOrMethod; - return; - } - - // check that all arguments are lockable objects - SmallVector<Expr*, 1> Args; - checkAttrArgsAreLockableObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true); - unsigned Size = Args.size(); - Expr **StartArg = Size == 0 ? 0 : &Args[0]; - - D->addAttr(::new (S.Context) - UnlockFunctionAttr(Attr.getRange(), S.Context, StartArg, Size, - Attr.getAttributeSpellingListIndex())); -} - static void handleLockReturnedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type) - << Attr.getName() << ThreadExpectedFunctionOrMethod; - return; - } - // check that the argument is lockable object SmallVector<Expr*, 1> Args; - checkAttrArgsAreLockableObjs(S, D, Attr, Args); + checkAttrArgsAreCapabilityObjs(S, D, Attr, Args); unsigned Size = Args.size(); if (Size == 0) return; @@ -969,15 +732,9 @@ static void handleLocksExcludedAttr(Sema &S, Decl *D, if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) return; - if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type) - << Attr.getName() << ThreadExpectedFunctionOrMethod; - return; - } - // check that all arguments are lockable objects SmallVector<Expr*, 1> Args; - checkAttrArgsAreLockableObjs(S, D, Attr, Args); + checkAttrArgsAreCapabilityObjs(S, D, Attr, Args); unsigned Size = Args.size(); if (Size == 0) return; @@ -988,6 +745,34 @@ static void handleLocksExcludedAttr(Sema &S, Decl *D, Attr.getAttributeSpellingListIndex())); } +static void handleEnableIfAttr(Sema &S, Decl *D, const AttributeList &Attr) { + Expr *Cond = Attr.getArgAsExpr(0); + if (!Cond->isTypeDependent()) { + ExprResult Converted = S.PerformContextuallyConvertToBool(Cond); + if (Converted.isInvalid()) + return; + Cond = Converted.get(); + } + + StringRef Msg; + if (!S.checkStringLiteralArgumentAttr(Attr, 1, Msg)) + return; + + SmallVector<PartialDiagnosticAt, 8> Diags; + if (!Cond->isValueDependent() && + !Expr::isPotentialConstantExprUnevaluated(Cond, cast<FunctionDecl>(D), + Diags)) { + S.Diag(Attr.getLoc(), diag::err_enable_if_never_constant_expr); + for (int I = 0, N = Diags.size(); I != N; ++I) + S.Diag(Diags[I].first, Diags[I].second); + return; + } + + D->addAttr(::new (S.Context) + EnableIfAttr(Attr.getRange(), S.Context, Cond, Msg, + Attr.getAttributeSpellingListIndex())); +} + static void handleConsumableAttr(Sema &S, Decl *D, const AttributeList &Attr) { ConsumableAttr::ConsumedState DefaultState; @@ -1004,18 +789,13 @@ static void handleConsumableAttr(Sema &S, Decl *D, const AttributeList &Attr) { << Attr.getName() << AANT_ArgumentIdentifier; return; } - - if (!isa<CXXRecordDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << - Attr.getName() << ExpectedClass; - return; - } D->addAttr(::new (S.Context) ConsumableAttr(Attr.getRange(), S.Context, DefaultState, Attr.getAttributeSpellingListIndex())); } + static bool checkForConsumableClass(Sema &S, const CXXMethodDecl *MD, const AttributeList &Attr) { ASTContext &CurrContext = S.getASTContext(); @@ -1038,12 +818,6 @@ static void handleCallableWhenAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) return; - - if (!isa<CXXMethodDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << - Attr.getName() << ExpectedMethod; - return; - } if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), Attr)) return; @@ -1076,13 +850,7 @@ static void handleCallableWhenAttr(Sema &S, Decl *D, static void handleParamTypestateAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!checkAttributeNumArgs(S, Attr, 1)) return; - - if (!isa<ParmVarDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << - Attr.getName() << ExpectedParameter; - return; - } - + ParamTypestateAttr::ConsumedState ParamState; if (Attr.isArgIdent(0)) { @@ -1123,12 +891,6 @@ static void handleReturnTypestateAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!checkAttributeNumArgs(S, Attr, 1)) return; - if (!(isa<FunctionDecl>(D) || isa<ParmVarDecl>(D))) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << - Attr.getName() << ExpectedFunctionMethodOrParameter; - return; - } - ReturnTypestateAttr::ConsumedState ReturnState; if (Attr.isArgIdent(0)) { @@ -1179,12 +941,6 @@ static void handleReturnTypestateAttr(Sema &S, Decl *D, static void handleSetTypestateAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!checkAttributeNumArgs(S, Attr, 1)) return; - - if (!isa<CXXMethodDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << - Attr.getName() << ExpectedMethod; - return; - } if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), Attr)) return; @@ -1214,12 +970,6 @@ static void handleTestTypestateAttr(Sema &S, Decl *D, if (!checkAttributeNumArgs(S, Attr, 1)) return; - if (!isa<CXXMethodDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << - Attr.getName() << ExpectedMethod; - return; - } - if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), Attr)) return; @@ -1245,21 +995,14 @@ static void handleTestTypestateAttr(Sema &S, Decl *D, static void handleExtVectorTypeAttr(Sema &S, Scope *scope, Decl *D, const AttributeList &Attr) { - TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D); - if (TD == 0) { - // __attribute__((ext_vector_type(N))) can only be applied to typedefs - // and type-ids. - S.Diag(Attr.getLoc(), diag::err_typecheck_ext_vector_not_typedef); - return; - } - // Remember this typedef decl, we will need it later for diagnostics. - S.ExtVectorDecls.push_back(TD); + S.ExtVectorDecls.push_back(cast<TypedefNameDecl>(D)); } static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (TagDecl *TD = dyn_cast<TagDecl>(D)) - TD->addAttr(::new (S.Context) PackedAttr(Attr.getRange(), S.Context)); + TD->addAttr(::new (S.Context) PackedAttr(Attr.getRange(), S.Context, + Attr.getAttributeSpellingListIndex())); 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. @@ -1276,28 +1019,6 @@ static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); } -static void handleMsStructAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (RecordDecl *RD = dyn_cast<RecordDecl>(D)) - RD->addAttr(::new (S.Context) - MsStructAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); - else - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); -} - -static void handleIBAction(Sema &S, Decl *D, const AttributeList &Attr) { - // The IBAction attributes only apply to instance methods. - if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) - if (MD->isInstanceMethod()) { - D->addAttr(::new (S.Context) - IBActionAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); - return; - } - - S.Diag(Attr.getLoc(), diag::warn_attribute_ibaction) << Attr.getName(); -} - static bool checkIBOutletCommon(Sema &S, Decl *D, const AttributeList &Attr) { // The IBOutlet/IBOutletCollection attributes only apply to instance // variables or properties of Objective-C classes. The outlet must also @@ -1359,7 +1080,7 @@ static void handleIBOutletCollection(Sema &S, Decl *D, } } - TypeSourceInfo *QTLoc = 0; + TypeSourceInfo *QTLoc = nullptr; QualType QT = S.GetTypeFromParser(PT, &QTLoc); if (!QTLoc) QTLoc = S.Context.getTrivialTypeSourceInfo(QT, Attr.getLoc()); @@ -1384,9 +1105,8 @@ static void possibleTransparentUnionPointerType(QualType &T) { if (const RecordType *UT = T->getAsUnionType()) if (UT && UT->getDecl()->hasAttr<TransparentUnionAttr>()) { RecordDecl *UD = UT->getDecl(); - for (RecordDecl::field_iterator it = UD->field_begin(), - itend = UD->field_end(); it != itend; ++it) { - QualType QT = it->getType(); + for (const auto *I : UD->fields()) { + QualType QT = I->getType(); if (QT->isAnyPointerType() || QT->isBlockPointerType()) { T = QT; return; @@ -1395,74 +1115,34 @@ static void possibleTransparentUnionPointerType(QualType &T) { } } -static void handleAllocSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!isFunctionOrMethod(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunctionOrMethod; - return; - } +static bool attrNonNullArgCheck(Sema &S, QualType T, const AttributeList &Attr, + SourceRange R, bool isReturnValue = false) { + T = T.getNonReferenceType(); + possibleTransparentUnionPointerType(T); - if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) - return; - - SmallVector<unsigned, 8> SizeArgs; - for (unsigned i = 0; i < Attr.getNumArgs(); ++i) { - Expr *Ex = Attr.getArgAsExpr(i); - uint64_t Idx; - if (!checkFunctionOrMethodArgumentIndex(S, D, Attr.getName()->getName(), - Attr.getLoc(), i + 1, Ex, Idx)) - return; - - // check if the function argument is of an integer type - QualType T = getFunctionOrMethodArgType(D, Idx).getNonReferenceType(); - if (!T->isIntegerType()) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) - << Attr.getName() << AANT_ArgumentIntegerConstant - << Ex->getSourceRange(); - return; - } - SizeArgs.push_back(Idx); - } - - // check if the function returns a pointer - if (!getFunctionType(D)->getResultType()->isAnyPointerType()) { - S.Diag(Attr.getLoc(), diag::warn_ns_attribute_wrong_return_type) - << Attr.getName() << 0 /*function*/<< 1 /*pointer*/ << D->getSourceRange(); + if (!T->isAnyPointerType() && !T->isBlockPointerType()) { + S.Diag(Attr.getLoc(), + isReturnValue ? diag::warn_attribute_return_pointers_only + : diag::warn_attribute_pointers_only) + << Attr.getName() << R; + return false; } - - D->addAttr(::new (S.Context) - AllocSizeAttr(Attr.getRange(), S.Context, - SizeArgs.data(), SizeArgs.size(), - Attr.getAttributeSpellingListIndex())); + return true; } static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) { - // 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() << ExpectedFunction; - return; - } - SmallVector<unsigned, 8> NonNullArgs; for (unsigned i = 0; i < Attr.getNumArgs(); ++i) { Expr *Ex = Attr.getArgAsExpr(i); uint64_t Idx; - if (!checkFunctionOrMethodArgumentIndex(S, D, Attr.getName()->getName(), - Attr.getLoc(), i + 1, Ex, Idx)) + if (!checkFunctionOrMethodParameterIndex(S, D, Attr, i + 1, Ex, Idx)) return; // Is the function argument a pointer type? - QualType T = getFunctionOrMethodArgType(D, Idx).getNonReferenceType(); - possibleTransparentUnionPointerType(T); - - if (!T->isAnyPointerType() && !T->isBlockPointerType()) { - // FIXME: Should also highlight argument in decl. - S.Diag(Attr.getLoc(), diag::warn_nonnull_pointers_only) - << "nonnull" << Ex->getSourceRange(); + // FIXME: Should also highlight argument in decl in the diagnostic. + if (!attrNonNullArgCheck(S, getFunctionOrMethodParamType(D, Idx), Attr, + Ex->getSourceRange())) continue; - } NonNullArgs.push_back(Idx); } @@ -1470,8 +1150,8 @@ static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) { // 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).getNonReferenceType(); + for (unsigned i = 0, e = getFunctionOrMethodNumParams(D); i != e; ++i) { + QualType T = getFunctionOrMethodParamType(D, i).getNonReferenceType(); possibleTransparentUnionPointerType(T); if (T->isAnyPointerType() || T->isBlockPointerType()) NonNullArgs.push_back(i); @@ -1495,13 +1175,37 @@ static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) { Attr.getAttributeSpellingListIndex())); } -static const char *ownershipKindToDiagName(OwnershipAttr::OwnershipKind K) { - switch (K) { - case OwnershipAttr::Holds: return "'ownership_holds'"; - case OwnershipAttr::Takes: return "'ownership_takes'"; - case OwnershipAttr::Returns: return "'ownership_returns'"; +static void handleNonNullAttrParameter(Sema &S, ParmVarDecl *D, + const AttributeList &Attr) { + if (Attr.getNumArgs() > 0) { + if (D->getFunctionType()) { + handleNonNullAttr(S, D, Attr); + } else { + S.Diag(Attr.getLoc(), diag::warn_attribute_nonnull_parm_no_args) + << D->getSourceRange(); + } + return; } - llvm_unreachable("unknown ownership"); + + // Is the argument a pointer type? + if (!attrNonNullArgCheck(S, D->getType(), Attr, D->getSourceRange())) + return; + + D->addAttr(::new (S.Context) + NonNullAttr(Attr.getRange(), S.Context, nullptr, 0, + Attr.getAttributeSpellingListIndex())); +} + +static void handleReturnsNonNullAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + QualType ResultType = getFunctionOrMethodResultType(D); + if (!attrNonNullArgCheck(S, ResultType, Attr, Attr.getRange(), + /* isReturnValue */ true)) + return; + + D->addAttr(::new (S.Context) + ReturnsNonNullAttr(Attr.getRange(), S.Context, + Attr.getAttributeSpellingListIndex())); } static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) { @@ -1519,58 +1223,49 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) { return; } - // Figure out our Kind, and check arguments while we're at it. - OwnershipAttr::OwnershipKind K; - switch (AL.getKind()) { - case AttributeList::AT_ownership_takes: - K = OwnershipAttr::Takes; - if (AL.getNumArgs() < 2) { - S.Diag(AL.getLoc(), diag::err_attribute_too_few_arguments) << 2; - return; - } - break; - case AttributeList::AT_ownership_holds: - K = OwnershipAttr::Holds; + // Figure out our Kind. + OwnershipAttr::OwnershipKind K = + OwnershipAttr(AL.getLoc(), S.Context, nullptr, nullptr, 0, + AL.getAttributeSpellingListIndex()).getOwnKind(); + + // Check arguments. + switch (K) { + case OwnershipAttr::Takes: + case OwnershipAttr::Holds: if (AL.getNumArgs() < 2) { - S.Diag(AL.getLoc(), diag::err_attribute_too_few_arguments) << 2; + S.Diag(AL.getLoc(), diag::err_attribute_too_few_arguments) + << AL.getName() << 2; return; } break; - case AttributeList::AT_ownership_returns: - K = OwnershipAttr::Returns; - + case OwnershipAttr::Returns: if (AL.getNumArgs() > 2) { - S.Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) << 1; + S.Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) + << AL.getName() << 1; return; } break; - default: - // This should never happen given how we are called. - llvm_unreachable("Unknown ownership attribute"); } - if (!isFunction(D) || !hasFunctionProto(D)) { - S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) - << AL.getName() << ExpectedFunction; - return; - } - - StringRef Module = AL.getArgAsIdent(0)->Ident->getName(); + IdentifierInfo *Module = AL.getArgAsIdent(0)->Ident; // Normalize the argument, __foo__ becomes foo. - if (Module.startswith("__") && Module.endswith("__")) - Module = Module.substr(2, Module.size() - 4); + StringRef ModuleName = Module->getName(); + if (ModuleName.startswith("__") && ModuleName.endswith("__") && + ModuleName.size() > 4) { + ModuleName = ModuleName.drop_front(2).drop_back(2); + Module = &S.PP.getIdentifierTable().get(ModuleName); + } SmallVector<unsigned, 8> OwnershipArgs; for (unsigned i = 1; i < AL.getNumArgs(); ++i) { Expr *Ex = AL.getArgAsExpr(i); uint64_t Idx; - if (!checkFunctionOrMethodArgumentIndex(S, D, AL.getName()->getName(), - AL.getLoc(), i, Ex, Idx)) + if (!checkFunctionOrMethodParameterIndex(S, D, AL, i, Ex, Idx)) return; // Is the function argument a pointer type? - QualType T = getFunctionOrMethodArgType(D, Idx); + QualType T = getFunctionOrMethodParamType(D, Idx); int Err = -1; // No error switch (K) { case OwnershipAttr::Takes: @@ -1590,13 +1285,13 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) { } // Check we don't have a conflict with another ownership attribute. - for (specific_attr_iterator<OwnershipAttr> - i = D->specific_attr_begin<OwnershipAttr>(), - e = D->specific_attr_end<OwnershipAttr>(); i != e; ++i) { - if ((*i)->getOwnKind() != K && (*i)->args_end() != - std::find((*i)->args_begin(), (*i)->args_end(), Idx)) { + for (const auto *I : D->specific_attrs<OwnershipAttr>()) { + // FIXME: A returns attribute should conflict with any returns attribute + // with a different index too. + if (I->getOwnKind() != K && I->args_end() != + std::find(I->args_begin(), I->args_end(), Idx)) { S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) - << AL.getName() << ownershipKindToDiagName((*i)->getOwnKind()); + << AL.getName() << I; return; } } @@ -1608,7 +1303,7 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) { llvm::array_pod_sort(start, start + size); D->addAttr(::new (S.Context) - OwnershipAttr(AL.getLoc(), S.Context, K, Module, start, size, + OwnershipAttr(AL.getLoc(), S.Context, Module, start, size, AL.getAttributeSpellingListIndex())); } @@ -1620,12 +1315,6 @@ static void handleWeakRefAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - if (!isa<VarDecl>(D) && !isa<FunctionDecl>(D)) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) - << Attr.getName() << ExpectedVariableOrFunction; - return; - } - NamedDecl *nd = cast<NamedDecl>(D); // gcc rejects @@ -1640,8 +1329,8 @@ static void handleWeakRefAttr(Sema &S, Decl *D, const AttributeList &Attr) { // we reject them const DeclContext *Ctx = D->getDeclContext()->getRedeclContext(); if (!Ctx->isFileContext()) { - S.Diag(Attr.getLoc(), diag::err_attribute_weakref_not_global_context) << - nd->getNameAsString(); + S.Diag(Attr.getLoc(), diag::err_attribute_weakref_not_global_context) + << nd; return; } @@ -1698,77 +1387,22 @@ static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) { Attr.getAttributeSpellingListIndex())); } -static void handleMinSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!isa<FunctionDecl>(D) && !isa<ObjCMethodDecl>(D)) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunctionOrMethod; - return; - } - - D->addAttr(::new (S.Context) - MinSizeAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); -} - static void handleColdAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!isa<FunctionDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunction; + if (checkAttrMutualExclusion<HotAttr>(S, D, Attr)) return; - } - - if (D->hasAttr<HotAttr>()) { - S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible) - << Attr.getName() << "hot"; - return; - } D->addAttr(::new (S.Context) ColdAttr(Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); } static void handleHotAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!isa<FunctionDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunction; - return; - } - - if (D->hasAttr<ColdAttr>()) { - S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible) - << Attr.getName() << "cold"; + if (checkAttrMutualExclusion<ColdAttr>(S, D, Attr)) return; - } D->addAttr(::new (S.Context) HotAttr(Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); } -static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!isa<FunctionDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunction; - return; - } - - D->addAttr(::new (S.Context) - NakedAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); -} - -static void handleAlwaysInlineAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!isa<FunctionDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunction; - return; - } - - D->addAttr(::new (S.Context) - AlwaysInlineAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); -} - static void handleTLSModelAttr(Sema &S, Decl *D, const AttributeList &Attr) { StringRef Model; @@ -1777,12 +1411,6 @@ static void handleTLSModelAttr(Sema &S, Decl *D, if (!S.checkStringLiteralArgumentAttr(Attr, 0, Model, &LiteralLoc)) return; - if (!isa<VarDecl>(D) || !cast<VarDecl>(D)->getTLSKind()) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) - << Attr.getName() << ExpectedTLSVar; - return; - } - // Check that the value. if (Model != "global-dynamic" && Model != "local-dynamic" && Model != "initial-exec" && Model != "local-exec") { @@ -1797,7 +1425,7 @@ static void handleTLSModelAttr(Sema &S, Decl *D, static void handleMallocAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - QualType RetTy = FD->getResultType(); + QualType RetTy = FD->getReturnType(); if (RetTy->isAnyPointerType() || RetTy->isBlockPointerType()) { D->addAttr(::new (S.Context) MallocAttr(Attr.getRange(), S.Context, @@ -1809,35 +1437,15 @@ static void handleMallocAttr(Sema &S, Decl *D, const AttributeList &Attr) { S.Diag(Attr.getLoc(), diag::warn_attribute_malloc_pointer_only); } -static void handleMayAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) { - D->addAttr(::new (S.Context) - MayAliasAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); -} - -static void handleNoCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (isa<VarDecl>(D)) - D->addAttr(::new (S.Context) - NoCommonAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); - else - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedVariable; -} - static void handleCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (S.LangOpts.CPlusPlus) { - S.Diag(Attr.getLoc(), diag::err_common_not_supported_cplusplus); + S.Diag(Attr.getLoc(), diag::err_attribute_not_supported_in_lang) + << Attr.getName() << AttributeLangSupport::Cpp; return; } - if (isa<VarDecl>(D)) - D->addAttr(::new (S.Context) - CommonAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); - else - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedVariable; + D->addAttr(::new (S.Context) CommonAttr(Attr.getRange(), S.Context, + Attr.getAttributeSpellingListIndex())); } static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &attr) { @@ -1872,8 +1480,8 @@ static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D, // because 'analyzer_noreturn' does not impact the type. if (!isFunctionOrMethod(D) && !isa<BlockDecl>(D)) { ValueDecl *VD = dyn_cast<ValueDecl>(D); - if (VD == 0 || (!VD->getType()->isBlockPointerType() - && !VD->getType()->isFunctionPointerType())) { + if (!VD || (!VD->getType()->isBlockPointerType() && + !VD->getType()->isFunctionPointerType())) { S.Diag(Attr.getLoc(), Attr.isCXX11Attribute() ? diag::err_attribute_wrong_decl_type : diag::warn_attribute_wrong_decl_type) @@ -1887,23 +1495,6 @@ static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D, Attr.getAttributeSpellingListIndex())); } -static void handleCXX11NoReturnAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - // C++11 [dcl.attr.noreturn]p1: - // The attribute may be applied to the declarator-id in a function - // declaration. - FunctionDecl *FD = dyn_cast<FunctionDecl>(D); - if (!FD) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunctionOrMethod; - return; - } - - D->addAttr(::new (S.Context) - CXX11NoReturnAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); -} - // PS3 PPU-specific. static void handleVecReturnAttr(Sema &S, Decl *D, const AttributeList &Attr) { /* @@ -1929,14 +1520,8 @@ static void handleVecReturnAttr(Sema &S, Decl *D, const AttributeList &Attr) { return result; // This will be returned in a register } */ - if (!isa<RecordDecl>(D)) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) - << Attr.getName() << ExpectedClass; - return; - } - - if (D->getAttr<VecReturnAttr>()) { - S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << "vecreturn"; + if (VecReturnAttr *A = D->getAttr<VecReturnAttr>()) { + S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << A; return; } @@ -1953,9 +1538,8 @@ static void handleVecReturnAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - for (RecordDecl::field_iterator iter = record->field_begin(); - iter != record->field_end(); iter++) { - if ((count == 1) || !iter->getType()->isVectorType()) { + for (const auto *I : record->fields()) { + if ((count == 1) || !I->getType()->isVectorType()) { S.Diag(Attr.getLoc(), diag::err_attribute_vecreturn_only_vector_member); return; } @@ -1977,10 +1561,6 @@ static void handleDependencyAttr(Sema &S, Scope *Scope, Decl *D, diag::err_carries_dependency_param_not_function_decl); return; } - } else if (!isa<FunctionDecl>(D)) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunctionMethodOrParameter; - return; } D->addAttr(::new (S.Context) CarriesDependencyAttr( @@ -1988,36 +1568,10 @@ static void handleDependencyAttr(Sema &S, Scope *Scope, Decl *D, Attr.getAttributeSpellingListIndex())); } -static void handleUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!isa<VarDecl>(D) && !isa<ObjCIvarDecl>(D) && !isFunctionOrMethod(D) && - !isa<TypeDecl>(D) && !isa<LabelDecl>(D) && !isa<FieldDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedVariableFunctionOrLabel; - return; - } - - D->addAttr(::new (S.Context) - UnusedAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); -} - -static void handleReturnsTwiceAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!isa<FunctionDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunction; - return; - } - - D->addAttr(::new (S.Context) - ReturnsTwiceAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); -} - static void handleUsedAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { if (VD->hasLocalStorage()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "used"; + S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); return; } } else if (!isFunctionOrMethod(D)) { @@ -2034,29 +1588,15 @@ static void handleUsedAttr(Sema &S, Decl *D, const AttributeList &Attr) { static void handleConstructorAttr(Sema &S, Decl *D, const AttributeList &Attr) { // check the attribute arguments. if (Attr.getNumArgs() > 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 1; + S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) + << Attr.getName() << 1; return; } - int priority = 65535; // FIXME: Do not hardcode such constants. - if (Attr.getNumArgs() > 0) { - Expr *E = Attr.getArgAsExpr(0); - llvm::APSInt Idx(32); - if (E->isTypeDependent() || E->isValueDependent() || - !E->isIntegerConstantExpr(Idx, S.Context)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) - << Attr.getName() << 1 << AANT_ArgumentIntegerConstant - << E->getSourceRange(); - return; - } - priority = Idx.getZExtValue(); - } - - if (!isa<FunctionDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunction; + uint32_t priority = ConstructorAttr::DefaultPriority; + if (Attr.getNumArgs() > 0 && + !checkUInt32Argument(S, Attr, Attr.getArgAsExpr(0), priority)) return; - } D->addAttr(::new (S.Context) ConstructorAttr(Attr.getRange(), S.Context, priority, @@ -2066,29 +1606,15 @@ static void handleConstructorAttr(Sema &S, Decl *D, const AttributeList &Attr) { static void handleDestructorAttr(Sema &S, Decl *D, const AttributeList &Attr) { // check the attribute arguments. if (Attr.getNumArgs() > 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 1; + S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) + << Attr.getName() << 1; return; } - int priority = 65535; // FIXME: Do not hardcode such constants. - if (Attr.getNumArgs() > 0) { - Expr *E = Attr.getArgAsExpr(0); - llvm::APSInt Idx(32); - if (E->isTypeDependent() || E->isValueDependent() || - !E->isIntegerConstantExpr(Idx, S.Context)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) - << Attr.getName() << 1 << AANT_ArgumentIntegerConstant - << E->getSourceRange(); - return; - } - priority = Idx.getZExtValue(); - } - - if (!isa<FunctionDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunction; + uint32_t priority = DestructorAttr::DefaultPriority; + if (Attr.getNumArgs() > 0 && + !checkUInt32Argument(S, Attr, Attr.getArgAsExpr(0), priority)) return; - } D->addAttr(::new (S.Context) DestructorAttr(Attr.getRange(), S.Context, priority, @@ -2100,7 +1626,8 @@ static void handleAttrWithMessage(Sema &S, Decl *D, const AttributeList &Attr) { unsigned NumArgs = Attr.getNumArgs(); if (NumArgs > 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 1; + S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) + << Attr.getName() << 1; return; } @@ -2113,36 +1640,17 @@ static void handleAttrWithMessage(Sema &S, Decl *D, Attr.getAttributeSpellingListIndex())); } -static void handleArcWeakrefUnavailableAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - D->addAttr(::new (S.Context) - ArcWeakrefUnavailableAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); -} - -static void handleObjCRootClassAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!isa<ObjCInterfaceDecl>(D)) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) - << Attr.getName() << ExpectedObjectiveCInterface; +static void handleObjCSuppresProtocolAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + if (!cast<ObjCProtocolDecl>(D)->isThisDeclarationADefinition()) { + S.Diag(Attr.getLoc(), diag::err_objc_attr_protocol_requires_definition) + << Attr.getName() << Attr.getRange(); return; } - - D->addAttr(::new (S.Context) - ObjCRootClassAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); -} -static void handleObjCRequiresPropertyDefsAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!isa<ObjCInterfaceDecl>(D)) { - S.Diag(Attr.getLoc(), diag::err_suppress_autosynthesis); - return; - } - D->addAttr(::new (S.Context) - ObjCRequiresPropertyDefsAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + ObjCExplicitProtocolImplAttr(Attr.getRange(), S.Context, + Attr.getAttributeSpellingListIndex())); } static bool checkAvailabilityAttr(Sema &S, SourceRange Range, @@ -2312,7 +1820,7 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range, MergedIntroduced == Introduced && MergedDeprecated == Deprecated && MergedObsoleted == Obsoleted) - return NULL; + return nullptr; // Only create a new attribute if !Override, but we want to do // the checking. @@ -2324,7 +1832,7 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range, Obsoleted, IsUnavailable, Message, AttrSpellingListIndex); } - return NULL; + return nullptr; } static void handleAvailabilityAttr(Sema &S, Decl *D, @@ -2373,7 +1881,7 @@ static T *mergeVisibilityAttr(Sema &S, Decl *D, SourceRange range, if (existingAttr) { typename T::VisibilityType existingValue = existingAttr->getVisibility(); if (existingValue == value) - return NULL; + return nullptr; S.Diag(existingAttr->getLocation(), diag::err_mismatched_visibility); S.Diag(range.getBegin(), diag::note_previous_attribute); D->dropAttr<T>(); @@ -2450,13 +1958,7 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr, static void handleObjCMethodFamilyAttr(Sema &S, Decl *decl, const AttributeList &Attr) { - ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(decl); - if (!method) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) - << ExpectedMethod; - return; - } - + ObjCMethodDecl *method = cast<ObjCMethodDecl>(decl); if (!Attr.isArgIdent(0)) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) << Attr.getName() << 1 << AANT_ArgumentIdentifier; @@ -2471,30 +1973,17 @@ static void handleObjCMethodFamilyAttr(Sema &S, Decl *decl, return; } - if (F == ObjCMethodFamilyAttr::OMF_init && - !method->getResultType()->isObjCObjectPointerType()) { + if (F == ObjCMethodFamilyAttr::OMF_init && + !method->getReturnType()->isObjCObjectPointerType()) { S.Diag(method->getLocation(), diag::err_init_method_bad_return_type) - << method->getResultType(); + << method->getReturnType(); // Ignore the attribute. return; } method->addAttr(new (S.Context) ObjCMethodFamilyAttr(Attr.getRange(), - S.Context, F)); -} - -static void handleObjCExceptionAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - ObjCInterfaceDecl *OCI = dyn_cast<ObjCInterfaceDecl>(D); - if (OCI == 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) - << Attr.getName() << ExpectedObjectiveCInterface; - return; - } - - D->addAttr(::new (S.Context) - ObjCExceptionAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + S.Context, F, + Attr.getAttributeSpellingListIndex())); } static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) { @@ -2526,18 +2015,6 @@ static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) { Attr.getAttributeSpellingListIndex())); } -static void -handleOverloadableAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!isa<FunctionDecl>(D)) { - S.Diag(Attr.getLoc(), diag::err_attribute_overloadable_not_function); - return; - } - - D->addAttr(::new (S.Context) - OverloadableAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); -} - static void handleBlocksAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!Attr.isArgIdent(0)) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) @@ -2561,11 +2038,12 @@ static void handleBlocksAttr(Sema &S, Decl *D, const AttributeList &Attr) { static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) { // check the attribute arguments. if (Attr.getNumArgs() > 2) { - S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 2; + S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) + << Attr.getName() << 2; return; } - unsigned sentinel = 0; + unsigned sentinel = (unsigned)SentinelAttr::DefaultSentinel; if (Attr.getNumArgs() > 0) { Expr *E = Attr.getArgAsExpr(0); llvm::APSInt Idx(32); @@ -2586,7 +2064,7 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) { sentinel = Idx.getZExtValue(); } - unsigned nullPos = 0; + unsigned nullPos = (unsigned)SentinelAttr::DefaultNullPos; if (Attr.getNumArgs() > 1) { Expr *E = Attr.getArgAsExpr(1); llvm::APSInt Idx(32); @@ -2632,7 +2110,8 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) { } 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) + const FunctionType *FT = Ty->isFunctionPointerType() + ? D->getFunctionType() : Ty->getAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>(); if (!cast<FunctionProtoType>(FT)->isVariadic()) { int m = Ty->isFunctionPointerType() ? 0 : 1; @@ -2654,27 +2133,15 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) { Attr.getAttributeSpellingListIndex())); } -static void handleWarnUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (RecordDecl *RD = dyn_cast<RecordDecl>(D)) - RD->addAttr(::new (S.Context) WarnUnusedAttr(Attr.getRange(), S.Context)); - else - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); -} - static void handleWarnUnusedResult(Sema &S, Decl *D, const AttributeList &Attr) { - if (!isFunction(D) && !isa<ObjCMethodDecl>(D) && !isa<CXXRecordDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunctionMethodOrClass; - return; - } - - if (isFunction(D) && getFunctionType(D)->getResultType()->isVoidType()) { + if (D->getFunctionType() && + D->getFunctionType()->getReturnType()->isVoidType()) { S.Diag(Attr.getLoc(), diag::warn_attribute_void_function_method) << Attr.getName() << 0; return; } if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) - if (MD->getResultType()->isVoidType()) { + if (MD->getReturnType()->isVoidType()) { S.Diag(Attr.getLoc(), diag::warn_attribute_void_function_method) << Attr.getName() << 1; return; @@ -2685,24 +2152,6 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const AttributeList &Attr) Attr.getAttributeSpellingListIndex())); } -static void handleWeakAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!isa<VarDecl>(D) && !isa<FunctionDecl>(D)) { - if (isa<CXXRecordDecl>(D)) { - D->addAttr(::new (S.Context) WeakAttr(Attr.getRange(), S.Context)); - return; - } - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedVariableOrFunction; - return; - } - - NamedDecl *nd = cast<NamedDecl>(D); - - nd->addAttr(::new (S.Context) - WeakAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); -} - static void handleWeakImportAttr(Sema &S, Decl *D, const AttributeList &Attr) { // weak_import only applies to variable & function declarations. bool isDef = false; @@ -2727,66 +2176,40 @@ static void handleWeakImportAttr(Sema &S, Decl *D, const AttributeList &Attr) { } // Handles reqd_work_group_size and work_group_size_hint. +template <typename WorkGroupAttr> static void handleWorkGroupSize(Sema &S, Decl *D, const AttributeList &Attr) { - unsigned WGSize[3]; + uint32_t WGSize[3]; for (unsigned i = 0; i < 3; ++i) { - Expr *E = Attr.getArgAsExpr(i); - llvm::APSInt ArgNum(32); - if (E->isTypeDependent() || E->isValueDependent() || - !E->isIntegerConstantExpr(ArgNum, S.Context)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) - << Attr.getName() << AANT_ArgumentIntegerConstant - << E->getSourceRange(); + const Expr *E = Attr.getArgAsExpr(i); + if (!checkUInt32Argument(S, Attr, E, WGSize[i], i)) + return; + if (WGSize[i] == 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_is_zero) + << Attr.getName() << E->getSourceRange(); return; } - WGSize[i] = (unsigned) ArgNum.getZExtValue(); - } - - if (Attr.getKind() == AttributeList::AT_ReqdWorkGroupSize - && D->hasAttr<ReqdWorkGroupSizeAttr>()) { - ReqdWorkGroupSizeAttr *A = D->getAttr<ReqdWorkGroupSizeAttr>(); - if (!(A->getXDim() == WGSize[0] && - A->getYDim() == WGSize[1] && - A->getZDim() == WGSize[2])) { - S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute) << - Attr.getName(); - } } - if (Attr.getKind() == AttributeList::AT_WorkGroupSizeHint - && D->hasAttr<WorkGroupSizeHintAttr>()) { - WorkGroupSizeHintAttr *A = D->getAttr<WorkGroupSizeHintAttr>(); - if (!(A->getXDim() == WGSize[0] && - A->getYDim() == WGSize[1] && - A->getZDim() == WGSize[2])) { - S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute) << - Attr.getName(); - } - } + WorkGroupAttr *Existing = D->getAttr<WorkGroupAttr>(); + if (Existing && !(Existing->getXDim() == WGSize[0] && + Existing->getYDim() == WGSize[1] && + Existing->getZDim() == WGSize[2])) + S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute) << Attr.getName(); - if (Attr.getKind() == AttributeList::AT_ReqdWorkGroupSize) - D->addAttr(::new (S.Context) - ReqdWorkGroupSizeAttr(Attr.getRange(), S.Context, - WGSize[0], WGSize[1], WGSize[2], - Attr.getAttributeSpellingListIndex())); - else - D->addAttr(::new (S.Context) - WorkGroupSizeHintAttr(Attr.getRange(), S.Context, - WGSize[0], WGSize[1], WGSize[2], + D->addAttr(::new (S.Context) WorkGroupAttr(Attr.getRange(), S.Context, + WGSize[0], WGSize[1], WGSize[2], Attr.getAttributeSpellingListIndex())); } static void handleVecTypeHint(Sema &S, Decl *D, const AttributeList &Attr) { - assert(Attr.getKind() == AttributeList::AT_VecTypeHint); - if (!Attr.hasParsedType()) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << Attr.getName() << 1; return; } - TypeSourceInfo *ParmTSI = 0; + TypeSourceInfo *ParmTSI = nullptr; QualType ParmType = S.GetTypeFromParser(Attr.getTypeArg(), &ParmTSI); assert(ParmTSI && "no type source info for attribute argument"); @@ -2798,9 +2221,7 @@ static void handleVecTypeHint(Sema &S, Decl *D, const AttributeList &Attr) { return; } - if (Attr.getKind() == AttributeList::AT_VecTypeHint && - D->hasAttr<VecTypeHintAttr>()) { - VecTypeHintAttr *A = D->getAttr<VecTypeHintAttr>(); + if (VecTypeHintAttr *A = D->getAttr<VecTypeHintAttr>()) { if (!S.Context.hasSameType(A->getTypeHint(), ParmType)) { S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute) << Attr.getName(); return; @@ -2808,7 +2229,8 @@ static void handleVecTypeHint(Sema &S, Decl *D, const AttributeList &Attr) { } D->addAttr(::new (S.Context) VecTypeHintAttr(Attr.getLoc(), S.Context, - ParmTSI)); + ParmTSI, + Attr.getAttributeSpellingListIndex())); } SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range, @@ -2816,10 +2238,10 @@ SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range, unsigned AttrSpellingListIndex) { if (SectionAttr *ExistingAttr = D->getAttr<SectionAttr>()) { if (ExistingAttr->getName() == Name) - return NULL; + return nullptr; Diag(ExistingAttr->getLocation(), diag::warn_mismatched_section); Diag(Range.getBegin(), diag::note_previous_attribute); - return NULL; + return nullptr; } return ::new (Context) SectionAttr(Range, Context, Name, AttrSpellingListIndex); @@ -2841,12 +2263,6 @@ static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - // This attribute cannot be applied to local variables. - if (isa<VarDecl>(D) && cast<VarDecl>(D)->hasLocalStorage()) { - S.Diag(LiteralLoc, diag::err_attribute_section_local_variable); - return; - } - unsigned Index = Attr.getAttributeSpellingListIndex(); SectionAttr *NewAttr = S.mergeSectionAttr(D, Attr.getRange(), Str, Index); if (NewAttr) @@ -2854,44 +2270,16 @@ static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) { } -static void handleNothrowAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (NoThrowAttr *Existing = D->getAttr<NoThrowAttr>()) { - if (Existing->getLocation().isInvalid()) - Existing->setRange(Attr.getRange()); - } else { - D->addAttr(::new (S.Context) - NoThrowAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); - } -} - -static void handleConstAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (ConstAttr *Existing = D->getAttr<ConstAttr>()) { - if (Existing->getLocation().isInvalid()) - Existing->setRange(Attr.getRange()); - } else { - D->addAttr(::new (S.Context) - ConstAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex() )); - } -} - -static void handlePureAttr(Sema &S, Decl *D, const AttributeList &Attr) { - D->addAttr(::new (S.Context) - PureAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); -} - static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) { - VarDecl *VD = dyn_cast<VarDecl>(D); - if (!VD || !VD->hasLocalStorage()) { + VarDecl *VD = cast<VarDecl>(D); + if (!VD->hasLocalStorage()) { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); return; } Expr *E = Attr.getArgAsExpr(0); SourceLocation Loc = E->getExprLoc(); - FunctionDecl *FD = 0; + FunctionDecl *FD = nullptr; DeclarationNameInfo NI; // gcc only allows for simple identifiers. Since we support more than gcc, we @@ -2948,20 +2336,13 @@ static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) { /// Handle __attribute__((format_arg((idx)))) attribute based on /// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html static void handleFormatArgAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!isFunctionOrMethod(D) || !hasFunctionProto(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunction; - return; - } - Expr *IdxExpr = Attr.getArgAsExpr(0); - uint64_t ArgIdx; - if (!checkFunctionOrMethodArgumentIndex(S, D, Attr.getName()->getName(), - Attr.getLoc(), 1, IdxExpr, ArgIdx)) + uint64_t Idx; + if (!checkFunctionOrMethodParameterIndex(S, D, Attr, 1, IdxExpr, Idx)) return; // make sure the format string is really a string - QualType Ty = getFunctionOrMethodArgType(D, ArgIdx); + QualType Ty = getFunctionOrMethodParamType(D, Idx); bool not_nsstring_type = !isNSStringType(Ty, S.Context); if (not_nsstring_type && @@ -2986,7 +2367,7 @@ static void handleFormatArgAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - // We cannot use the ArgIdx returned from checkFunctionOrMethodArgumentIndex + // We cannot use the Idx returned from checkFunctionOrMethodParameterIndex // because that has corrected for the implicit this parameter, and is zero- // based. The attribute expects what the user wrote explicitly. llvm::APSInt Val; @@ -3033,12 +2414,12 @@ static void handleInitPriorityAttr(Sema &S, Decl *D, return; } - if (!isa<VarDecl>(D) || S.getCurFunctionOrMethodDecl()) { + if (S.getCurFunctionOrMethodDecl()) { S.Diag(Attr.getLoc(), diag::err_init_priority_object_attr); Attr.setInvalid(); return; } - QualType T = dyn_cast<VarDecl>(D)->getType(); + QualType T = cast<VarDecl>(D)->getType(); if (S.Context.getAsArrayType(T)) T = S.Context.getBaseElementType(T); if (!T->getAs<RecordType>()) { @@ -3046,22 +2427,17 @@ static void handleInitPriorityAttr(Sema &S, Decl *D, Attr.setInvalid(); return; } - - Expr *priorityExpr = Attr.getArgAsExpr(0); - - llvm::APSInt priority(32); - if (priorityExpr->isTypeDependent() || priorityExpr->isValueDependent() || - !priorityExpr->isIntegerConstantExpr(priority, S.Context)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) - << Attr.getName() << AANT_ArgumentIntegerConstant - << priorityExpr->getSourceRange(); + + Expr *E = Attr.getArgAsExpr(0); + uint32_t prioritynum; + if (!checkUInt32Argument(S, Attr, E, prioritynum)) { Attr.setInvalid(); return; } - unsigned prioritynum = priority.getZExtValue(); + if (prioritynum < 101 || prioritynum > 65535) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_outof_range) - << priorityExpr->getSourceRange(); + << E->getSourceRange(); Attr.setInvalid(); return; } @@ -3075,19 +2451,15 @@ FormatAttr *Sema::mergeFormatAttr(Decl *D, SourceRange Range, int FirstArg, unsigned AttrSpellingListIndex) { // Check whether we already have an equivalent format attribute. - for (specific_attr_iterator<FormatAttr> - i = D->specific_attr_begin<FormatAttr>(), - e = D->specific_attr_end<FormatAttr>(); - i != e ; ++i) { - FormatAttr *f = *i; - if (f->getType() == Format && - f->getFormatIdx() == FormatIdx && - f->getFirstArg() == FirstArg) { + for (auto *F : D->specific_attrs<FormatAttr>()) { + if (F->getType() == Format && + F->getFormatIdx() == FormatIdx && + F->getFirstArg() == FirstArg) { // If we don't have a valid location for this attribute, adopt the // location. - if (f->getLocation().isInvalid()) - f->setRange(Range); - return NULL; + if (F->getLocation().isInvalid()) + F->setRange(Range); + return nullptr; } } @@ -3104,17 +2476,10 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - if (!isFunctionOrMethodOrBlock(D) || !hasFunctionProto(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunction; - return; - } - // In C++ the implicit 'this' function parameter also counts, and they are // counted from one. bool HasImplicitThisParam = isInstanceMethod(D); - unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam; - unsigned FirstIdx = 1; + unsigned NumArgs = getFunctionOrMethodNumParams(D) + HasImplicitThisParam; IdentifierInfo *II = Attr.getArgAsIdent(0)->Ident; StringRef Format = II->getName(); @@ -3134,29 +2499,24 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (Kind == InvalidFormat) { S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) - << "format" << II->getName(); + << Attr.getName() << II->getName(); return; } // checks for the 2nd argument Expr *IdxExpr = Attr.getArgAsExpr(1); - llvm::APSInt Idx(32); - if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() || - !IdxExpr->isIntegerConstantExpr(Idx, S.Context)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) - << Attr.getName() << 2 << AANT_ArgumentIntegerConstant - << IdxExpr->getSourceRange(); + uint32_t Idx; + if (!checkUInt32Argument(S, Attr, IdxExpr, Idx, 2)) return; - } - if (Idx.getZExtValue() < FirstIdx || Idx.getZExtValue() > NumArgs) { + if (Idx < 1 || Idx > NumArgs) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds) - << "format" << 2 << IdxExpr->getSourceRange(); + << Attr.getName() << 2 << IdxExpr->getSourceRange(); return; } // FIXME: Do we need to bounds check? - unsigned ArgIdx = Idx.getZExtValue() - 1; + unsigned ArgIdx = Idx - 1; if (HasImplicitThisParam) { if (ArgIdx == 0) { @@ -3169,7 +2529,7 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) { } // make sure the format string is really a string - QualType Ty = getFunctionOrMethodArgType(D, ArgIdx); + QualType Ty = getFunctionOrMethodParamType(D, ArgIdx); if (Kind == CFStringFormat) { if (!isCFStringType(Ty, S.Context)) { @@ -3196,14 +2556,9 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) { // check the 3rd argument Expr *FirstArgExpr = Attr.getArgAsExpr(2); - llvm::APSInt FirstArg(32); - if (FirstArgExpr->isTypeDependent() || FirstArgExpr->isValueDependent() || - !FirstArgExpr->isIntegerConstantExpr(FirstArg, S.Context)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) - << Attr.getName() << 3 << AANT_ArgumentIntegerConstant - << FirstArgExpr->getSourceRange(); + uint32_t FirstArg; + if (!checkUInt32Argument(S, Attr, FirstArgExpr, FirstArg, 3)) return; - } // check if the function is variadic if the 3rd argument non-zero if (FirstArg != 0) { @@ -3226,13 +2581,12 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) { // if 0 it disables parameter checking (to use with e.g. va_list) } else if (FirstArg != 0 && FirstArg != NumArgs) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds) - << "format" << 3 << FirstArgExpr->getSourceRange(); + << Attr.getName() << 3 << FirstArgExpr->getSourceRange(); return; } FormatAttr *NewAttr = S.mergeFormatAttr(D, Attr.getRange(), II, - Idx.getZExtValue(), - FirstArg.getZExtValue(), + Idx, FirstArg, Attr.getAttributeSpellingListIndex()); if (NewAttr) D->addAttr(NewAttr); @@ -3241,7 +2595,7 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) { static void handleTransparentUnionAttr(Sema &S, Decl *D, const AttributeList &Attr) { // Try to find the underlying union declaration. - RecordDecl *RD = 0; + RecordDecl *RD = nullptr; TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D); if (TD && TD->getUnderlyingType()->isUnionType()) RD = TD->getUnderlyingType()->getAsUnionType()->getDecl(); @@ -3280,8 +2634,13 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D, uint64_t FirstAlign = S.Context.getTypeAlign(FirstType); for (; Field != FieldEnd; ++Field) { QualType FieldType = Field->getType(); + // FIXME: this isn't fully correct; we also need to test whether the + // members of the union would all have the same calling convention as the + // first member of the union. Checking just the size and alignment isn't + // sufficient (consider structs passed on the stack instead of in registers + // as an example). if (S.Context.getTypeSize(FieldType) != FirstSize || - S.Context.getTypeAlign(FieldType) != FirstAlign) { + 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) @@ -3310,10 +2669,8 @@ static void handleAnnotateAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; // Don't duplicate annotations that are already set. - for (specific_attr_iterator<AnnotateAttr> - i = D->specific_attr_begin<AnnotateAttr>(), - e = D->specific_attr_end<AnnotateAttr>(); i != e; ++i) { - if ((*i)->getAnnotation() == Str) + for (const auto *I : D->specific_attrs<AnnotateAttr>()) { + if (I->getAnnotation() == Str) return; } @@ -3332,7 +2689,7 @@ static void handleAlignedAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (Attr.getNumArgs() == 0) { D->addAttr(::new (S.Context) AlignedAttr(Attr.getRange(), S.Context, - true, 0, Attr.getAttributeSpellingListIndex())); + true, nullptr, Attr.getAttributeSpellingListIndex())); return; } @@ -3380,15 +2737,14 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, if (FD->isBitField()) DiagKind = 3; } else if (!isa<TagDecl>(D)) { - Diag(AttrLoc, diag::err_attribute_wrong_decl_type) - << (TmpAttr.isC11() ? "'_Alignas'" : "'alignas'") + Diag(AttrLoc, diag::err_attribute_wrong_decl_type) << &TmpAttr << (TmpAttr.isC11() ? ExpectedVariableOrField : ExpectedVariableFieldOrTag); return; } if (DiagKind != -1) { Diag(AttrLoc, diag::err_alignas_attribute_wrong_decl_type) - << TmpAttr.isC11() << DiagKind; + << &TmpAttr << DiagKind; return; } } @@ -3422,18 +2778,16 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, return; } - if (TmpAttr.isDeclspec()) { - // We've already verified it's a power of 2, now let's make sure it's - // 8192 or less. - if (Alignment.getZExtValue() > 8192) { - Diag(AttrLoc, diag::err_attribute_aligned_greater_than_8192) - << E->getSourceRange(); - return; - } + // Alignment calculations can wrap around if it's greater than 2**28. + unsigned MaxValidAlignment = TmpAttr.isDeclspec() ? 8192 : 268435456; + if (Alignment.getZExtValue() > MaxValidAlignment) { + Diag(AttrLoc, diag::err_attribute_aligned_too_great) << MaxValidAlignment + << E->getSourceRange(); + return; } AlignedAttr *AA = ::new (Context) AlignedAttr(AttrRange, Context, true, - ICE.take(), SpellingListIndex); + ICE.get(), SpellingListIndex); AA->setPackExpansion(IsPackExpansion); D->addAttr(AA); } @@ -3463,15 +2817,13 @@ void Sema::CheckAlignasUnderalignment(Decl *D) { // The combined effect of all alignment attributes in a declaration shall // not specify an alignment that is less strict than the alignment that // would otherwise be required for the entity being declared. - AlignedAttr *AlignasAttr = 0; + AlignedAttr *AlignasAttr = nullptr; unsigned Align = 0; - for (specific_attr_iterator<AlignedAttr> - I = D->specific_attr_begin<AlignedAttr>(), - E = D->specific_attr_end<AlignedAttr>(); I != E; ++I) { + for (auto *I : D->specific_attrs<AlignedAttr>()) { if (I->isAlignmentDependent()) return; if (I->isAlignas()) - AlignasAttr = *I; + AlignasAttr = I; Align = std::max(Align, I->getAlignment(Context)); } @@ -3484,6 +2836,35 @@ void Sema::CheckAlignasUnderalignment(Decl *D) { } } +bool Sema::checkMSInheritanceAttrOnDefinition( + CXXRecordDecl *RD, SourceRange Range, bool BestCase, + MSInheritanceAttr::Spelling SemanticSpelling) { + assert(RD->hasDefinition() && "RD has no definition!"); + + // We may not have seen base specifiers or any virtual methods yet. We will + // have to wait until the record is defined to catch any mismatches. + if (!RD->getDefinition()->isCompleteDefinition()) + return false; + + // The unspecified model never matches what a definition could need. + if (SemanticSpelling == MSInheritanceAttr::Keyword_unspecified_inheritance) + return false; + + if (BestCase) { + if (RD->calculateInheritanceModel() == SemanticSpelling) + return false; + } else { + if (RD->calculateInheritanceModel() <= SemanticSpelling) + return false; + } + + Diag(Range.getBegin(), diag::err_mismatched_ms_inheritance) + << 0 /*definition*/; + Diag(RD->getDefinition()->getLocation(), diag::note_defined_here) + << RD->getNameAsString(); + return true; +} + /// handleModeAttr - This attribute modifies the width of a decl with primitive /// type. /// @@ -3553,7 +2934,7 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) { OldTy = VD->getType(); else { S.Diag(D->getLocation(), diag::err_attr_wrong_decl) - << "mode" << Attr.getRange(); + << Attr.getName() << Attr.getRange(); return; } @@ -3575,7 +2956,7 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) { // FIXME: Make sure floating-point mappings are accurate // FIXME: Support XF and TF types if (!DestWidth) { - S.Diag(Attr.getLoc(), diag::err_unknown_machine_mode) << Name; + S.Diag(Attr.getLoc(), diag::err_machine_mode) << 0 /*Unknown*/ << Name; return; } @@ -3588,7 +2969,7 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) { NewTy = S.Context.getRealTypeForBitwidth(DestWidth); if (NewTy.isNull()) { - S.Diag(Attr.getLoc(), diag::err_unsupported_machine_mode) << Name; + S.Diag(Attr.getLoc(), diag::err_machine_mode) << 1 /*Unsupported*/ << Name; return; } @@ -3625,141 +3006,44 @@ static void handleNoDebugAttr(Sema &S, Decl *D, const AttributeList &Attr) { Attr.getAttributeSpellingListIndex())); } -static void handleNoInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!isa<FunctionDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunction; +static void handleAlwaysInlineAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + if (checkAttrMutualExclusion<OptimizeNoneAttr>(S, D, Attr)) return; - } D->addAttr(::new (S.Context) - NoInlineAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + AlwaysInlineAttr(Attr.getRange(), S.Context, + Attr.getAttributeSpellingListIndex())); } -static void handleNoInstrumentFunctionAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!isa<FunctionDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunction; +static void handleOptimizeNoneAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + if (checkAttrMutualExclusion<AlwaysInlineAttr>(S, D, Attr)) return; - } D->addAttr(::new (S.Context) - NoInstrumentFunctionAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); -} - -static void handleConstantAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (S.LangOpts.CUDA) { - if (!isa<VarDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedVariable; - return; - } - - D->addAttr(::new (S.Context) - CUDAConstantAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); - } else { - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "constant"; - } -} - -static void handleDeviceAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (S.LangOpts.CUDA) { - // check the attribute arguments. - if (Attr.getNumArgs() != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) - << Attr.getName() << 0; - return; - } - - if (!isa<FunctionDecl>(D) && !isa<VarDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedVariableOrFunction; - return; - } - - D->addAttr(::new (S.Context) - CUDADeviceAttr(Attr.getRange(), S.Context, + OptimizeNoneAttr(Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); - } else { - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "device"; - } } static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (S.LangOpts.CUDA) { - if (!isa<FunctionDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunction; - return; - } - - FunctionDecl *FD = cast<FunctionDecl>(D); - if (!FD->getResultType()->isVoidType()) { - TypeLoc TL = FD->getTypeSourceInfo()->getTypeLoc().IgnoreParens(); - if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) { - S.Diag(FD->getTypeSpecStartLoc(), diag::err_kern_type_not_void_return) - << FD->getType() - << FixItHint::CreateReplacement(FTL.getResultLoc().getSourceRange(), - "void"); - } else { - S.Diag(FD->getTypeSpecStartLoc(), diag::err_kern_type_not_void_return) - << FD->getType(); - } - return; - } - - D->addAttr(::new (S.Context) - CUDAGlobalAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); - } else { - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "global"; + FunctionDecl *FD = cast<FunctionDecl>(D); + if (!FD->getReturnType()->isVoidType()) { + SourceRange RTRange = FD->getReturnTypeSourceRange(); + S.Diag(FD->getTypeSpecStartLoc(), diag::err_kern_type_not_void_return) + << FD->getType() + << (RTRange.isValid() ? FixItHint::CreateReplacement(RTRange, "void") + : FixItHint()); + return; } -} -static void handleHostAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (S.LangOpts.CUDA) { - if (!isa<FunctionDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunction; - return; - } - - D->addAttr(::new (S.Context) - CUDAHostAttr(Attr.getRange(), S.Context, + D->addAttr(::new (S.Context) + CUDAGlobalAttr(Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); - } else { - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "host"; - } -} - -static void handleSharedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (S.LangOpts.CUDA) { - if (!isa<VarDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedVariable; - return; - } - - D->addAttr(::new (S.Context) - CUDASharedAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); - } else { - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "shared"; - } } static void handleGNUInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) { - FunctionDecl *Fn = dyn_cast<FunctionDecl>(D); - if (Fn == 0) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunction; - return; - } - + FunctionDecl *Fn = cast<FunctionDecl>(D); if (!Fn->isInlineSpecified()) { S.Diag(Attr.getLoc(), diag::warn_gnu_inline_attribute_requires_inline); return; @@ -3856,25 +3140,6 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) { } } -static void handleOpenCLKernelAttr(Sema &S, Decl *D, const AttributeList &Attr){ - D->addAttr(::new (S.Context) OpenCLKernelAttr(Attr.getRange(), S.Context)); -} - -static void handleOpenCLImageAccessAttr(Sema &S, Decl *D, const AttributeList &Attr){ - Expr *E = Attr.getArgAsExpr(0); - llvm::APSInt ArgNum(32); - if (E->isTypeDependent() || E->isValueDependent() || - !E->isIntegerConstantExpr(ArgNum, S.Context)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) - << Attr.getName() << AANT_ArgumentIntegerConstant - << E->getSourceRange(); - return; - } - - D->addAttr(::new (S.Context) OpenCLImageAccessAttr( - Attr.getRange(), S.Context, ArgNum.getZExtValue())); -} - bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, const FunctionDecl *FD) { if (attr.isInvalid()) @@ -3886,8 +3151,7 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, return true; } - // TODO: diagnose uses of these conventions on the wrong target. Or, better - // move to TargetAttributesSema one day. + // TODO: diagnose uses of these conventions on the wrong target. switch (attr.getKind()) { case AttributeList::AT_CDecl: CC = CC_C; break; case AttributeList::AT_FastCall: CC = CC_X86FastCall; break; @@ -3940,24 +3204,6 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, return false; } -static void handleRegparmAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (hasDeclarator(D)) return; - - unsigned numParams; - if (S.CheckRegparmAttr(Attr, numParams)) - return; - - if (!isa<ObjCMethodDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunctionOrMethod; - return; - } - - D->addAttr(::new (S.Context) - RegparmAttr(Attr.getRange(), S.Context, numParams, - Attr.getAttributeSpellingListIndex())); -} - /// Checks a regparm attribute, returning true if it is ill-formed and /// otherwise setting numParams to the appropriate value. bool Sema::CheckRegparmAttr(const AttributeList &Attr, unsigned &numParams) { @@ -3969,13 +3215,9 @@ bool Sema::CheckRegparmAttr(const AttributeList &Attr, unsigned &numParams) { return true; } + uint32_t NP; Expr *NumParamsExpr = Attr.getArgAsExpr(0); - llvm::APSInt NumParams(32); - if (NumParamsExpr->isTypeDependent() || NumParamsExpr->isValueDependent() || - !NumParamsExpr->isIntegerConstantExpr(NumParams, Context)) { - Diag(Attr.getLoc(), diag::err_attribute_argument_type) - << Attr.getName() << AANT_ArgumentIntegerConstant - << NumParamsExpr->getSourceRange(); + if (!checkUInt32Argument(*this, Attr, NumParamsExpr, NP)) { Attr.setInvalid(); return true; } @@ -3987,7 +3229,7 @@ bool Sema::CheckRegparmAttr(const AttributeList &Attr, unsigned &numParams) { return true; } - numParams = NumParams.getZExtValue(); + numParams = NP; if (numParams > Context.getTargetInfo().getRegParmMax()) { Diag(Attr.getLoc(), diag::err_attribute_regparm_invalid_number) << Context.getTargetInfo().getRegParmMax() << NumParamsExpr->getSourceRange(); @@ -3998,53 +3240,28 @@ bool Sema::CheckRegparmAttr(const AttributeList &Attr, unsigned &numParams) { return false; } -static void handleLaunchBoundsAttr(Sema &S, Decl *D, const AttributeList &Attr){ - if (S.LangOpts.CUDA) { - // check the attribute arguments. - if (Attr.getNumArgs() != 1 && Attr.getNumArgs() != 2) { - // FIXME: 0 is not okay. - S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 2; - return; - } - - if (!isFunctionOrMethod(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunctionOrMethod; - return; - } - - Expr *MaxThreadsExpr = Attr.getArgAsExpr(0); - llvm::APSInt MaxThreads(32); - if (MaxThreadsExpr->isTypeDependent() || - MaxThreadsExpr->isValueDependent() || - !MaxThreadsExpr->isIntegerConstantExpr(MaxThreads, S.Context)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) - << Attr.getName() << 1 << AANT_ArgumentIntegerConstant - << MaxThreadsExpr->getSourceRange(); - return; - } +static void handleLaunchBoundsAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + // check the attribute arguments. + if (Attr.getNumArgs() != 1 && Attr.getNumArgs() != 2) { + // FIXME: 0 is not okay. + S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) + << Attr.getName() << 2; + return; + } - llvm::APSInt MinBlocks(32); - if (Attr.getNumArgs() > 1) { - Expr *MinBlocksExpr = Attr.getArgAsExpr(1); - if (MinBlocksExpr->isTypeDependent() || - MinBlocksExpr->isValueDependent() || - !MinBlocksExpr->isIntegerConstantExpr(MinBlocks, S.Context)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) - << Attr.getName() << 2 << AANT_ArgumentIntegerConstant - << MinBlocksExpr->getSourceRange(); - return; - } - } + uint32_t MaxThreads, MinBlocks = 0; + if (!checkUInt32Argument(S, Attr, Attr.getArgAsExpr(0), MaxThreads, 1)) + return; + if (Attr.getNumArgs() > 1 && !checkUInt32Argument(S, Attr, + Attr.getArgAsExpr(1), + MinBlocks, 2)) + return; - D->addAttr(::new (S.Context) - CUDALaunchBoundsAttr(Attr.getRange(), S.Context, - MaxThreads.getZExtValue(), - MinBlocks.getZExtValue(), - Attr.getAttributeSpellingListIndex())); - } else { - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "launch_bounds"; - } + D->addAttr(::new (S.Context) + CUDALaunchBoundsAttr(Attr.getRange(), S.Context, + MaxThreads, MinBlocks, + Attr.getAttributeSpellingListIndex())); } static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D, @@ -4058,7 +3275,6 @@ static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D, if (!checkAttributeNumArgs(S, Attr, 3)) return; - StringRef AttrName = Attr.getName()->getName(); IdentifierInfo *ArgumentKind = Attr.getArgAsIdent(0)->Ident; if (!isFunctionOrMethod(D) || !hasFunctionProto(D)) { @@ -4068,21 +3284,19 @@ static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D, } uint64_t ArgumentIdx; - if (!checkFunctionOrMethodArgumentIndex(S, D, AttrName, - Attr.getLoc(), 2, - Attr.getArgAsExpr(1), ArgumentIdx)) + if (!checkFunctionOrMethodParameterIndex(S, D, Attr, 2, Attr.getArgAsExpr(1), + ArgumentIdx)) return; uint64_t TypeTagIdx; - if (!checkFunctionOrMethodArgumentIndex(S, D, AttrName, - Attr.getLoc(), 3, - Attr.getArgAsExpr(2), TypeTagIdx)) + if (!checkFunctionOrMethodParameterIndex(S, D, Attr, 3, Attr.getArgAsExpr(2), + TypeTagIdx)) return; - bool IsPointer = (AttrName == "pointer_with_type_tag"); + bool IsPointer = (Attr.getName()->getName() == "pointer_with_type_tag"); if (IsPointer) { // Ensure that buffer has a pointer type. - QualType BufferTy = getFunctionOrMethodArgType(D, ArgumentIdx); + QualType BufferTy = getFunctionOrMethodParamType(D, ArgumentIdx); if (!BufferTy->isPointerType()) { S.Diag(Attr.getLoc(), diag::err_attribute_pointers_only) << Attr.getName(); @@ -4106,8 +3320,14 @@ static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D, if (!checkAttributeNumArgs(S, Attr, 1)) return; + if (!isa<VarDecl>(D)) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) + << Attr.getName() << ExpectedVariable; + return; + } + IdentifierInfo *PointerKind = Attr.getArgAsIdent(0)->Ident; - TypeSourceInfo *MatchingCTypeLoc = 0; + TypeSourceInfo *MatchingCTypeLoc = nullptr; S.GetTypeFromParser(Attr.getMatchingCType(), &MatchingCTypeLoc); assert(MatchingCTypeLoc && "no type source info for attribute argument"); @@ -4123,6 +3343,11 @@ static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D, // Checker-specific attribute handlers. //===----------------------------------------------------------------------===// +static bool isValidSubjectOfNSReturnsRetainedAttribute(QualType type) { + return type->isDependentType() || + type->isObjCRetainableType(); +} + static bool isValidSubjectOfNSAttribute(Sema &S, QualType type) { return type->isDependentType() || type->isObjCObjectPointerType() || @@ -4135,14 +3360,9 @@ static bool isValidSubjectOfCFAttribute(Sema &S, QualType type) { } static void handleNSConsumedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - ParmVarDecl *param = dyn_cast<ParmVarDecl>(D); - if (!param) { - S.Diag(D->getLocStart(), diag::warn_attribute_wrong_decl_type) - << Attr.getRange() << Attr.getName() << ExpectedParameter; - return; - } - + ParmVarDecl *param = cast<ParmVarDecl>(D); bool typeOK, cf; + if (Attr.getKind() == AttributeList::AT_NSConsumed) { typeOK = isValidSubjectOfNSAttribute(S, param->getType()); cf = false; @@ -4167,33 +3387,20 @@ static void handleNSConsumedAttr(Sema &S, Decl *D, const AttributeList &Attr) { Attr.getAttributeSpellingListIndex())); } -static void handleNSConsumesSelfAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!isa<ObjCMethodDecl>(D)) { - S.Diag(D->getLocStart(), diag::warn_attribute_wrong_decl_type) - << Attr.getRange() << Attr.getName() << ExpectedMethod; - return; - } - - D->addAttr(::new (S.Context) - NSConsumesSelfAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); -} - static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, const AttributeList &Attr) { QualType returnType; if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) - returnType = MD->getResultType(); + returnType = MD->getReturnType(); else if (S.getLangOpts().ObjCAutoRefCount && hasDeclarator(D) && (Attr.getKind() == AttributeList::AT_NSReturnsRetained)) return; // ignore: was handled as a type attribute else if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D)) returnType = PD->getType(); else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) - returnType = FD->getResultType(); + returnType = FD->getReturnType(); else { S.Diag(D->getLocStart(), diag::warn_attribute_wrong_decl_type) << Attr.getRange() << Attr.getName() @@ -4205,8 +3412,12 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, bool cf; switch (Attr.getKind()) { default: llvm_unreachable("invalid ownership attribute"); - case AttributeList::AT_NSReturnsAutoreleased: case AttributeList::AT_NSReturnsRetained: + typeOK = isValidSubjectOfNSReturnsRetainedAttribute(returnType); + cf = false; + break; + + case AttributeList::AT_NSReturnsAutoreleased: case AttributeList::AT_NSReturnsNotRetained: typeOK = isValidSubjectOfNSAttribute(S, returnType); cf = false; @@ -4263,27 +3474,17 @@ static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D, SourceLocation loc = attr.getLoc(); QualType resultType; - - ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(D); - - if (!method) { - ObjCPropertyDecl *property = dyn_cast<ObjCPropertyDecl>(D); - if (!property) { - S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type) - << SourceRange(loc, loc) << attr.getName() << ExpectedMethodOrProperty; - return; - } - resultType = property->getType(); - } + if (isa<ObjCMethodDecl>(D)) + resultType = cast<ObjCMethodDecl>(D)->getReturnType(); else - // Check that the method returns a normal pointer. - resultType = method->getResultType(); + resultType = cast<ObjCPropertyDecl>(D)->getType(); if (!resultType->isReferenceType() && (!resultType->isPointerType() || resultType->isObjCRetainableType())) { S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_return_type) << SourceRange(loc) - << attr.getName() << (method ? EP_ObjCMethod : EP_ObjCProperty) + << attr.getName() + << (isa<ObjCMethodDecl>(D) ? EP_ObjCMethod : EP_ObjCProperty) << /*non-retainable pointer*/ 2; // Drop the attribute. @@ -4297,14 +3498,8 @@ static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D, static void handleObjCRequiresSuperAttr(Sema &S, Decl *D, const AttributeList &attr) { - SourceLocation loc = attr.getLoc(); - ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(D); + ObjCMethodDecl *method = cast<ObjCMethodDecl>(D); - if (!method) { - S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type) - << SourceRange(loc, loc) << attr.getName() << ExpectedMethod; - return; - } DeclContext *DC = method->getDeclContext(); if (const ObjCProtocolDecl *PDecl = dyn_cast_or_null<ObjCProtocolDecl>(DC)) { S.Diag(D->getLocStart(), diag::warn_objc_requires_super_protocol) @@ -4323,97 +3518,94 @@ static void handleObjCRequiresSuperAttr(Sema &S, Decl *D, attr.getAttributeSpellingListIndex())); } -/// Handle cf_audited_transfer and cf_unknown_transfer. -static void handleCFTransferAttr(Sema &S, Decl *D, const AttributeList &A) { - if (!isa<FunctionDecl>(D)) { - S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type) - << A.getRange() << A.getName() << ExpectedFunction; +static void handleCFAuditedTransferAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + if (checkAttrMutualExclusion<CFUnknownTransferAttr>(S, D, Attr)) return; - } - bool IsAudited = (A.getKind() == AttributeList::AT_CFAuditedTransfer); + D->addAttr(::new (S.Context) + CFAuditedTransferAttr(Attr.getRange(), S.Context, + Attr.getAttributeSpellingListIndex())); +} - // Check whether there's a conflicting attribute already present. - Attr *Existing; - if (IsAudited) { - Existing = D->getAttr<CFUnknownTransferAttr>(); - } else { - Existing = D->getAttr<CFAuditedTransferAttr>(); - } - if (Existing) { - S.Diag(D->getLocStart(), diag::err_attributes_are_not_compatible) - << A.getName() - << (IsAudited ? "cf_unknown_transfer" : "cf_audited_transfer") - << A.getRange() << Existing->getRange(); +static void handleCFUnknownTransferAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + if (checkAttrMutualExclusion<CFAuditedTransferAttr>(S, D, Attr)) return; - } - // All clear; add the attribute. - if (IsAudited) { - D->addAttr(::new (S.Context) - CFAuditedTransferAttr(A.getRange(), S.Context, - A.getAttributeSpellingListIndex())); - } else { - D->addAttr(::new (S.Context) - CFUnknownTransferAttr(A.getRange(), S.Context, - A.getAttributeSpellingListIndex())); - } + D->addAttr(::new (S.Context) + CFUnknownTransferAttr(Attr.getRange(), S.Context, + Attr.getAttributeSpellingListIndex())); } -static void handleNSBridgedAttr(Sema &S, Scope *Sc, Decl *D, +static void handleObjCBridgeAttr(Sema &S, Scope *Sc, Decl *D, const AttributeList &Attr) { - RecordDecl *RD = dyn_cast<RecordDecl>(D); - if (!RD || RD->isUnion()) { - S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type) - << Attr.getRange() << Attr.getName() << ExpectedStruct; - } - - IdentifierLoc *Parm = Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : 0; - - // In Objective-C, verify that the type names an Objective-C type. - // We don't want to check this outside of ObjC because people sometimes - // do crazy C declarations of Objective-C types. - if (Parm && S.getLangOpts().ObjC1) { - // Check for an existing type with this name. - LookupResult R(S, DeclarationName(Parm->Ident), Parm->Loc, - Sema::LookupOrdinaryName); - if (S.LookupName(R, Sc)) { - NamedDecl *Target = R.getFoundDecl(); - if (Target && !isa<ObjCInterfaceDecl>(Target)) { - S.Diag(D->getLocStart(), diag::err_ns_bridged_not_interface); - S.Diag(Target->getLocStart(), diag::note_declared_at); - } - } - } + IdentifierLoc * Parm = Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : nullptr; + if (!Parm) { + S.Diag(D->getLocStart(), diag::err_objc_attr_not_id) << Attr.getName() << 0; + return; + } + D->addAttr(::new (S.Context) - NSBridgedAttr(Attr.getRange(), S.Context, Parm ? Parm->Ident : 0, + ObjCBridgeAttr(Attr.getRange(), S.Context, Parm->Ident, Attr.getAttributeSpellingListIndex())); } -static void handleObjCBridgeAttr(Sema &S, Scope *Sc, Decl *D, - const AttributeList &Attr) { - if (!isa<RecordDecl>(D)) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) - << Attr.getName() - << (S.getLangOpts().CPlusPlus ? ExpectedStructOrUnionOrClass - : ExpectedStructOrUnion); +static void handleObjCBridgeMutableAttr(Sema &S, Scope *Sc, Decl *D, + const AttributeList &Attr) { + IdentifierLoc * Parm = Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : nullptr; + + if (!Parm) { + S.Diag(D->getLocStart(), diag::err_objc_attr_not_id) << Attr.getName() << 0; return; } - if (Attr.getNumArgs() != 1) { - S.Diag(D->getLocStart(), diag::err_objc_bridge_not_id); + D->addAttr(::new (S.Context) + ObjCBridgeMutableAttr(Attr.getRange(), S.Context, Parm->Ident, + Attr.getAttributeSpellingListIndex())); +} + +static void handleObjCBridgeRelatedAttr(Sema &S, Scope *Sc, Decl *D, + const AttributeList &Attr) { + IdentifierInfo *RelatedClass = + Attr.isArgIdent(0) ? Attr.getArgAsIdent(0)->Ident : nullptr; + if (!RelatedClass) { + S.Diag(D->getLocStart(), diag::err_objc_attr_not_id) << Attr.getName() << 0; return; } - IdentifierLoc *Parm = Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : 0; - if (!Parm) { - S.Diag(D->getLocStart(), diag::err_objc_bridge_not_id); + IdentifierInfo *ClassMethod = + Attr.getArgAsIdent(1) ? Attr.getArgAsIdent(1)->Ident : nullptr; + IdentifierInfo *InstanceMethod = + Attr.getArgAsIdent(2) ? Attr.getArgAsIdent(2)->Ident : nullptr; + D->addAttr(::new (S.Context) + ObjCBridgeRelatedAttr(Attr.getRange(), S.Context, RelatedClass, + ClassMethod, InstanceMethod, + Attr.getAttributeSpellingListIndex())); +} + +static void handleObjCDesignatedInitializer(Sema &S, Decl *D, + const AttributeList &Attr) { + ObjCInterfaceDecl *IFace; + if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(D->getDeclContext())) + IFace = CatDecl->getClassInterface(); + else + IFace = cast<ObjCInterfaceDecl>(D->getDeclContext()); + IFace->setHasDesignatedInitializers(); + D->addAttr(::new (S.Context) + ObjCDesignatedInitializerAttr(Attr.getRange(), S.Context, + Attr.getAttributeSpellingListIndex())); +} + +static void handleObjCRuntimeName(Sema &S, Decl *D, + const AttributeList &Attr) { + StringRef MetaDataName; + if (!S.checkStringLiteralArgumentAttr(Attr, 0, MetaDataName)) return; - } - D->addAttr(::new (S.Context) - ObjCBridgeAttr(Attr.getRange(), S.Context, Parm ? Parm->Ident : 0, - Attr.getAttributeSpellingListIndex())); + ObjCRuntimeNameAttr(Attr.getRange(), S.Context, + MetaDataName, + Attr.getAttributeSpellingListIndex())); } static void handleObjCOwnershipAttr(Sema &S, Decl *D, @@ -4426,12 +3618,6 @@ static void handleObjCOwnershipAttr(Sema &S, Decl *D, static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!isa<VarDecl>(D) && !isa<FieldDecl>(D)) { - S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type) - << Attr.getRange() << Attr.getName() << ExpectedVariable; - return; - } - ValueDecl *vd = cast<ValueDecl>(D); QualType type = vd->getType(); @@ -4475,19 +3661,18 @@ static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D, // Microsoft specific attribute handlers. //===----------------------------------------------------------------------===// -// Check if MS extensions or some other language extensions are enabled. If -// not, issue a diagnostic that the given attribute is unused. -static bool checkMicrosoftExt(Sema &S, const AttributeList &Attr, - bool OtherExtension = false) { - if (S.LangOpts.MicrosoftExt || OtherExtension) - return true; - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); - return false; -} - static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkMicrosoftExt(S, Attr, S.LangOpts.Borland)) + if (!S.LangOpts.CPlusPlus) { + S.Diag(Attr.getLoc(), diag::err_attribute_not_supported_in_lang) + << Attr.getName() << AttributeLangSupport::C; + return; + } + + if (!isa<CXXRecordDecl>(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedClass; return; + } StringRef StrRef; SourceLocation LiteralLoc; @@ -4521,55 +3706,299 @@ static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) { Attr.getAttributeSpellingListIndex())); } -static void handleInheritanceAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkMicrosoftExt(S, Attr)) +static void handleMSInheritanceAttr(Sema &S, Decl *D, const AttributeList &Attr) { + if (!S.LangOpts.CPlusPlus) { + S.Diag(Attr.getLoc(), diag::err_attribute_not_supported_in_lang) + << Attr.getName() << AttributeLangSupport::C; return; + } + MSInheritanceAttr *IA = S.mergeMSInheritanceAttr( + D, Attr.getRange(), /*BestCase=*/true, + Attr.getAttributeSpellingListIndex(), + (MSInheritanceAttr::Spelling)Attr.getSemanticSpelling()); + if (IA) + D->addAttr(IA); +} - AttributeList::Kind Kind = Attr.getKind(); - if (Kind == AttributeList::AT_SingleInheritance) - D->addAttr( - ::new (S.Context) - SingleInheritanceAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); - else if (Kind == AttributeList::AT_MultipleInheritance) - D->addAttr( - ::new (S.Context) - MultipleInheritanceAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); - else if (Kind == AttributeList::AT_VirtualInheritance) - D->addAttr( - ::new (S.Context) - VirtualInheritanceAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); +static void handleDeclspecThreadAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + VarDecl *VD = cast<VarDecl>(D); + if (!S.Context.getTargetInfo().isTLSSupported()) { + S.Diag(Attr.getLoc(), diag::err_thread_unsupported); + return; + } + if (VD->getTSCSpec() != TSCS_unspecified) { + S.Diag(Attr.getLoc(), diag::err_declspec_thread_on_thread_variable); + return; + } + if (VD->hasLocalStorage()) { + S.Diag(Attr.getLoc(), diag::err_thread_non_global) << "__declspec(thread)"; + return; + } + VD->addAttr(::new (S.Context) ThreadAttr( + Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); } -static void handlePortabilityAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkMicrosoftExt(S, Attr)) +static void handleARMInterruptAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + // Check the attribute arguments. + if (Attr.getNumArgs() > 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) + << Attr.getName() << 1; + return; + } + + StringRef Str; + SourceLocation ArgLoc; + + if (Attr.getNumArgs() == 0) + Str = ""; + else if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &ArgLoc)) return; - AttributeList::Kind Kind = Attr.getKind(); - if (Kind == AttributeList::AT_Win64) - D->addAttr( - ::new (S.Context) Win64Attr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + ARMInterruptAttr::InterruptType Kind; + if (!ARMInterruptAttr::ConvertStrToInterruptType(Str, Kind)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) + << Attr.getName() << Str << ArgLoc; + return; + } + + unsigned Index = Attr.getAttributeSpellingListIndex(); + D->addAttr(::new (S.Context) + ARMInterruptAttr(Attr.getLoc(), S.Context, Kind, Index)); } -static void handleForceInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkMicrosoftExt(S, Attr)) +static void handleMSP430InterruptAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + if (!checkAttributeNumArgs(S, Attr, 1)) + return; + + if (!Attr.isArgExpr(0)) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) << Attr.getName() + << AANT_ArgumentIntegerConstant; + return; + } + + // FIXME: Check for decl - it should be void ()(void). + + Expr *NumParamsExpr = static_cast<Expr *>(Attr.getArgAsExpr(0)); + llvm::APSInt NumParams(32); + if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) + << Attr.getName() << AANT_ArgumentIntegerConstant + << NumParamsExpr->getSourceRange(); + return; + } + + unsigned Num = NumParams.getLimitedValue(255); + if ((Num & 1) || Num > 30) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds) + << Attr.getName() << (int)NumParams.getSExtValue() + << NumParamsExpr->getSourceRange(); return; + } + D->addAttr(::new (S.Context) - ForceInlineAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + MSP430InterruptAttr(Attr.getLoc(), S.Context, Num, + Attr.getAttributeSpellingListIndex())); + D->addAttr(UsedAttr::CreateImplicit(S.Context)); } -static void handleSelectAnyAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkMicrosoftExt(S, Attr)) +static void handleInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) { + // Dispatch the interrupt attribute based on the current target. + if (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::msp430) + handleMSP430InterruptAttr(S, D, Attr); + else + handleARMInterruptAttr(S, D, Attr); +} + +static void handleX86ForceAlignArgPointerAttr(Sema &S, Decl *D, + const AttributeList& Attr) { + // If we try to apply it to a function pointer, don't warn, but don't + // do anything, either. It doesn't matter anyway, because there's nothing + // special about calling a force_align_arg_pointer function. + ValueDecl *VD = dyn_cast<ValueDecl>(D); + if (VD && VD->getType()->isFunctionPointerType()) + return; + // Also don't warn on function pointer typedefs. + TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D); + if (TD && (TD->getUnderlyingType()->isFunctionPointerType() || + TD->getUnderlyingType()->isFunctionType())) + return; + // Attribute can only be applied to function types. + if (!isa<FunctionDecl>(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << /* function */0; return; - // Check linkage after possibly merging declaratinos. See - // checkAttributesAfterMerging(). + } + D->addAttr(::new (S.Context) - SelectAnyAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + X86ForceAlignArgPointerAttr(Attr.getRange(), S.Context, + Attr.getAttributeSpellingListIndex())); +} + +DLLImportAttr *Sema::mergeDLLImportAttr(Decl *D, SourceRange Range, + unsigned AttrSpellingListIndex) { + if (D->hasAttr<DLLExportAttr>()) { + Diag(Range.getBegin(), diag::warn_attribute_ignored) << "'dllimport'"; + return nullptr; + } + + if (D->hasAttr<DLLImportAttr>()) + return nullptr; + + return ::new (Context) DLLImportAttr(Range, Context, AttrSpellingListIndex); +} + +DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D, SourceRange Range, + unsigned AttrSpellingListIndex) { + if (DLLImportAttr *Import = D->getAttr<DLLImportAttr>()) { + Diag(Import->getLocation(), diag::warn_attribute_ignored) << Import; + D->dropAttr<DLLImportAttr>(); + } + + if (D->hasAttr<DLLExportAttr>()) + return nullptr; + + return ::new (Context) DLLExportAttr(Range, Context, AttrSpellingListIndex); +} + +static void handleDLLAttr(Sema &S, Decl *D, const AttributeList &A) { + if (isa<ClassTemplatePartialSpecializationDecl>(D) && + S.Context.getTargetInfo().getCXXABI().isMicrosoft()) { + S.Diag(A.getRange().getBegin(), diag::warn_attribute_ignored) + << A.getName(); + return; + } + + unsigned Index = A.getAttributeSpellingListIndex(); + Attr *NewAttr = A.getKind() == AttributeList::AT_DLLExport + ? (Attr *)S.mergeDLLExportAttr(D, A.getRange(), Index) + : (Attr *)S.mergeDLLImportAttr(D, A.getRange(), Index); + if (NewAttr) + D->addAttr(NewAttr); +} + +MSInheritanceAttr * +Sema::mergeMSInheritanceAttr(Decl *D, SourceRange Range, bool BestCase, + unsigned AttrSpellingListIndex, + MSInheritanceAttr::Spelling SemanticSpelling) { + if (MSInheritanceAttr *IA = D->getAttr<MSInheritanceAttr>()) { + if (IA->getSemanticSpelling() == SemanticSpelling) + return nullptr; + Diag(IA->getLocation(), diag::err_mismatched_ms_inheritance) + << 1 /*previous declaration*/; + Diag(Range.getBegin(), diag::note_previous_ms_inheritance); + D->dropAttr<MSInheritanceAttr>(); + } + + CXXRecordDecl *RD = cast<CXXRecordDecl>(D); + if (RD->hasDefinition()) { + if (checkMSInheritanceAttrOnDefinition(RD, Range, BestCase, + SemanticSpelling)) { + return nullptr; + } + } else { + if (isa<ClassTemplatePartialSpecializationDecl>(RD)) { + Diag(Range.getBegin(), diag::warn_ignored_ms_inheritance) + << 1 /*partial specialization*/; + return nullptr; + } + if (RD->getDescribedClassTemplate()) { + Diag(Range.getBegin(), diag::warn_ignored_ms_inheritance) + << 0 /*primary template*/; + return nullptr; + } + } + + return ::new (Context) + MSInheritanceAttr(Range, Context, BestCase, AttrSpellingListIndex); +} + +static void handleCapabilityAttr(Sema &S, Decl *D, const AttributeList &Attr) { + // The capability attributes take a single string parameter for the name of + // the capability they represent. The lockable attribute does not take any + // parameters. However, semantically, both attributes represent the same + // concept, and so they use the same semantic attribute. Eventually, the + // lockable attribute will be removed. + // + // For backward compatibility, any capability which has no specified string + // literal will be considered a "mutex." + StringRef N("mutex"); + SourceLocation LiteralLoc; + if (Attr.getKind() == AttributeList::AT_Capability && + !S.checkStringLiteralArgumentAttr(Attr, 0, N, &LiteralLoc)) + return; + + // Currently, there are only two names allowed for a capability: role and + // mutex (case insensitive). Diagnose other capability names. + if (!N.equals_lower("mutex") && !N.equals_lower("role")) + S.Diag(LiteralLoc, diag::warn_invalid_capability_name) << N; + + D->addAttr(::new (S.Context) CapabilityAttr(Attr.getRange(), S.Context, N, + Attr.getAttributeSpellingListIndex())); +} + +static void handleAssertCapabilityAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + D->addAttr(::new (S.Context) AssertCapabilityAttr(Attr.getRange(), S.Context, + Attr.getArgAsExpr(0), + Attr.getAttributeSpellingListIndex())); +} + +static void handleAcquireCapabilityAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + SmallVector<Expr*, 1> Args; + if (!checkLockFunAttrCommon(S, D, Attr, Args)) + return; + + D->addAttr(::new (S.Context) AcquireCapabilityAttr(Attr.getRange(), + S.Context, + Args.data(), Args.size(), + Attr.getAttributeSpellingListIndex())); +} + +static void handleTryAcquireCapabilityAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + SmallVector<Expr*, 2> Args; + if (!checkTryLockFunAttrCommon(S, D, Attr, Args)) + return; + + D->addAttr(::new (S.Context) TryAcquireCapabilityAttr(Attr.getRange(), + S.Context, + Attr.getArgAsExpr(0), + Args.data(), + Args.size(), + Attr.getAttributeSpellingListIndex())); +} + +static void handleReleaseCapabilityAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + // Check that all arguments are lockable objects. + SmallVector<Expr *, 1> Args; + checkAttrArgsAreCapabilityObjs(S, D, Attr, Args, 0, true); + + D->addAttr(::new (S.Context) ReleaseCapabilityAttr( + Attr.getRange(), S.Context, Args.data(), Args.size(), + Attr.getAttributeSpellingListIndex())); +} + +static void handleRequiresCapabilityAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) + return; + + // check that all arguments are lockable objects + SmallVector<Expr*, 1> Args; + checkAttrArgsAreCapabilityObjs(S, D, Attr, Args); + if (Args.empty()) + return; + + RequiresCapabilityAttr *RCA = ::new (S.Context) + RequiresCapabilityAttr(Attr.getRange(), S.Context, Args.data(), + Args.size(), Attr.getAttributeSpellingListIndex()); + + D->addAttr(RCA); } /// Handles semantic checking for features that are common to all attributes, @@ -4583,15 +4012,24 @@ static bool handleCommonAttributeFeatures(Sema &S, Scope *scope, Decl *D, // We also bail on unknown and ignored attributes because those are handled // as part of the target-specific handling logic. if (Attr.hasCustomParsing() || - Attr.getKind() == AttributeList::UnknownAttribute || - Attr.getKind() == AttributeList::IgnoredAttribute) + Attr.getKind() == AttributeList::UnknownAttribute) return false; + // Check whether the attribute requires specific language extensions to be + // enabled. + if (!Attr.diagnoseLangOpts(S)) + return true; + // If there are no optional arguments, then checking for the argument count // is trivial. if (Attr.getMinArgs() == Attr.getMaxArgs() && !checkAttributeNumArgs(S, Attr, Attr.getMinArgs())) return true; + + // Check whether the attribute appertains to the given subject. + if (!Attr.diagnoseAppertainsTo(S, D)) + return true; + return false; } @@ -4605,7 +4043,7 @@ static bool handleCommonAttributeFeatures(Sema &S, Scope *scope, Decl *D, static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const AttributeList &Attr, bool IncludeCXX11Attributes) { - if (Attr.isInvalid()) + if (Attr.isInvalid() || Attr.getKind() == AttributeList::IgnoredAttribute) return; // Ignore C++11 attributes on declarator chunks: they appertain to the type @@ -4613,145 +4051,282 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, if (Attr.isCXX11Attribute() && !IncludeCXX11Attributes) return; + // Unknown attributes are automatically warned on. Target-specific attributes + // which do not apply to the current target architecture are treated as + // though they were unknown attributes. + if (Attr.getKind() == AttributeList::UnknownAttribute || + !Attr.existsInTarget(S.Context.getTargetInfo().getTriple())) { + S.Diag(Attr.getLoc(), Attr.isDeclspecAttribute() + ? diag::warn_unhandled_ms_attribute_ignored + : diag::warn_unknown_attribute_ignored) + << Attr.getName(); + return; + } + if (handleCommonAttributeFeatures(S, scope, D, Attr)) return; switch (Attr.getKind()) { - case AttributeList::AT_IBAction: handleIBAction(S, D, Attr); break; - case AttributeList::AT_IBOutlet: handleIBOutlet(S, D, Attr); break; + default: + // Type attributes are handled elsewhere; silently move on. + assert(Attr.isTypeAttr() && "Non-type attribute not handled"); + break; + case AttributeList::AT_Interrupt: + handleInterruptAttr(S, D, Attr); + break; + case AttributeList::AT_X86ForceAlignArgPointer: + handleX86ForceAlignArgPointerAttr(S, D, Attr); + break; + case AttributeList::AT_DLLExport: + case AttributeList::AT_DLLImport: + handleDLLAttr(S, D, Attr); + break; + case AttributeList::AT_Mips16: + handleSimpleAttribute<Mips16Attr>(S, D, Attr); + break; + case AttributeList::AT_NoMips16: + handleSimpleAttribute<NoMips16Attr>(S, D, Attr); + break; + case AttributeList::AT_IBAction: + handleSimpleAttribute<IBActionAttr>(S, D, Attr); + break; + case AttributeList::AT_IBOutlet: + handleIBOutlet(S, D, Attr); + break; case AttributeList::AT_IBOutletCollection: - handleIBOutletCollection(S, D, Attr); break; - case AttributeList::AT_AddressSpace: - case AttributeList::AT_ObjCGC: - case AttributeList::AT_VectorSize: - case AttributeList::AT_NeonVectorType: - case AttributeList::AT_NeonPolyVectorType: - case AttributeList::AT_Ptr32: - case AttributeList::AT_Ptr64: - case AttributeList::AT_SPtr: - case AttributeList::AT_UPtr: - // Ignore these, these are type attributes, handled by - // ProcessTypeAttributes. - break; - case AttributeList::AT_Alias: handleAliasAttr (S, D, Attr); break; - case AttributeList::AT_Aligned: handleAlignedAttr (S, D, Attr); break; - case AttributeList::AT_AllocSize: handleAllocSizeAttr (S, D, Attr); break; + handleIBOutletCollection(S, D, Attr); + break; + case AttributeList::AT_Alias: + handleAliasAttr(S, D, Attr); + break; + case AttributeList::AT_Aligned: + handleAlignedAttr(S, D, Attr); + break; case AttributeList::AT_AlwaysInline: - handleAlwaysInlineAttr (S, D, Attr); break; + handleAlwaysInlineAttr(S, D, Attr); + break; case AttributeList::AT_AnalyzerNoReturn: - handleAnalyzerNoReturnAttr (S, D, Attr); break; - case AttributeList::AT_TLSModel: handleTLSModelAttr (S, D, Attr); break; - case AttributeList::AT_Annotate: handleAnnotateAttr (S, D, Attr); break; - case AttributeList::AT_Availability:handleAvailabilityAttr(S, D, Attr); break; + handleAnalyzerNoReturnAttr(S, D, Attr); + break; + case AttributeList::AT_TLSModel: + handleTLSModelAttr(S, D, Attr); + break; + case AttributeList::AT_Annotate: + handleAnnotateAttr(S, D, Attr); + break; + case AttributeList::AT_Availability: + handleAvailabilityAttr(S, D, Attr); + break; case AttributeList::AT_CarriesDependency: handleDependencyAttr(S, scope, D, Attr); break; - case AttributeList::AT_Common: handleCommonAttr (S, D, Attr); break; - case AttributeList::AT_CUDAConstant:handleConstantAttr (S, D, Attr); break; - case AttributeList::AT_Constructor: handleConstructorAttr (S, D, Attr); break; + case AttributeList::AT_Common: + handleCommonAttr(S, D, Attr); + break; + case AttributeList::AT_CUDAConstant: + handleSimpleAttribute<CUDAConstantAttr>(S, D, Attr); + break; + case AttributeList::AT_Constructor: + handleConstructorAttr(S, D, Attr); + break; case AttributeList::AT_CXX11NoReturn: - handleCXX11NoReturnAttr(S, D, Attr); + handleSimpleAttribute<CXX11NoReturnAttr>(S, D, Attr); break; case AttributeList::AT_Deprecated: handleAttrWithMessage<DeprecatedAttr>(S, D, Attr); break; - case AttributeList::AT_Destructor: handleDestructorAttr (S, D, Attr); break; + case AttributeList::AT_Destructor: + handleDestructorAttr(S, D, Attr); + break; + case AttributeList::AT_EnableIf: + handleEnableIfAttr(S, D, Attr); + break; case AttributeList::AT_ExtVectorType: handleExtVectorTypeAttr(S, scope, D, Attr); break; case AttributeList::AT_MinSize: - handleMinSizeAttr(S, D, Attr); - break; - case AttributeList::AT_Format: handleFormatAttr (S, D, Attr); break; - case AttributeList::AT_FormatArg: handleFormatArgAttr (S, D, Attr); break; - case AttributeList::AT_CUDAGlobal: handleGlobalAttr (S, D, Attr); break; - case AttributeList::AT_CUDADevice: handleDeviceAttr (S, D, Attr); break; - case AttributeList::AT_CUDAHost: handleHostAttr (S, D, Attr); break; - case AttributeList::AT_GNUInline: handleGNUInlineAttr (S, D, Attr); break; + handleSimpleAttribute<MinSizeAttr>(S, D, Attr); + break; + case AttributeList::AT_OptimizeNone: + handleOptimizeNoneAttr(S, D, Attr); + break; + case AttributeList::AT_Flatten: + handleSimpleAttribute<FlattenAttr>(S, D, Attr); + break; + case AttributeList::AT_Format: + handleFormatAttr(S, D, Attr); + break; + case AttributeList::AT_FormatArg: + handleFormatArgAttr(S, D, Attr); + break; + case AttributeList::AT_CUDAGlobal: + handleGlobalAttr(S, D, Attr); + break; + case AttributeList::AT_CUDADevice: + handleSimpleAttribute<CUDADeviceAttr>(S, D, Attr); + break; + case AttributeList::AT_CUDAHost: + handleSimpleAttribute<CUDAHostAttr>(S, D, Attr); + break; + case AttributeList::AT_GNUInline: + handleGNUInlineAttr(S, D, Attr); + break; case AttributeList::AT_CUDALaunchBounds: handleLaunchBoundsAttr(S, D, Attr); break; - case AttributeList::AT_Malloc: handleMallocAttr (S, D, Attr); break; - case AttributeList::AT_MayAlias: handleMayAliasAttr (S, D, Attr); break; - case AttributeList::AT_Mode: handleModeAttr (S, D, Attr); break; - case AttributeList::AT_NoCommon: handleNoCommonAttr (S, D, Attr); break; - case AttributeList::AT_NonNull: handleNonNullAttr (S, D, Attr); break; - case AttributeList::AT_Overloadable:handleOverloadableAttr(S, D, Attr); break; - case AttributeList::AT_ownership_returns: - case AttributeList::AT_ownership_takes: - case AttributeList::AT_ownership_holds: - handleOwnershipAttr (S, D, Attr); break; - case AttributeList::AT_Cold: handleColdAttr (S, D, Attr); break; - case AttributeList::AT_Hot: handleHotAttr (S, D, Attr); break; - case AttributeList::AT_Naked: handleNakedAttr (S, D, Attr); break; - case AttributeList::AT_NoReturn: handleNoReturnAttr (S, D, Attr); break; - case AttributeList::AT_NoThrow: handleNothrowAttr (S, D, Attr); break; - case AttributeList::AT_CUDAShared: handleSharedAttr (S, D, Attr); break; - case AttributeList::AT_VecReturn: handleVecReturnAttr (S, D, Attr); break; + case AttributeList::AT_Malloc: + handleMallocAttr(S, D, Attr); + break; + case AttributeList::AT_MayAlias: + handleSimpleAttribute<MayAliasAttr>(S, D, Attr); + break; + case AttributeList::AT_Mode: + handleModeAttr(S, D, Attr); + break; + case AttributeList::AT_NoCommon: + handleSimpleAttribute<NoCommonAttr>(S, D, Attr); + break; + case AttributeList::AT_NoSplitStack: + handleSimpleAttribute<NoSplitStackAttr>(S, D, Attr); + break; + case AttributeList::AT_NonNull: + if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(D)) + handleNonNullAttrParameter(S, PVD, Attr); + else + handleNonNullAttr(S, D, Attr); + break; + case AttributeList::AT_ReturnsNonNull: + handleReturnsNonNullAttr(S, D, Attr); + break; + case AttributeList::AT_Overloadable: + handleSimpleAttribute<OverloadableAttr>(S, D, Attr); + break; + case AttributeList::AT_Ownership: + handleOwnershipAttr(S, D, Attr); + break; + case AttributeList::AT_Cold: + handleColdAttr(S, D, Attr); + break; + case AttributeList::AT_Hot: + handleHotAttr(S, D, Attr); + break; + case AttributeList::AT_Naked: + handleSimpleAttribute<NakedAttr>(S, D, Attr); + break; + case AttributeList::AT_NoReturn: + handleNoReturnAttr(S, D, Attr); + break; + case AttributeList::AT_NoThrow: + handleSimpleAttribute<NoThrowAttr>(S, D, Attr); + break; + case AttributeList::AT_CUDAShared: + handleSimpleAttribute<CUDASharedAttr>(S, D, Attr); + break; + case AttributeList::AT_VecReturn: + handleVecReturnAttr(S, D, Attr); + break; case AttributeList::AT_ObjCOwnership: - handleObjCOwnershipAttr(S, D, Attr); break; + handleObjCOwnershipAttr(S, D, Attr); + break; case AttributeList::AT_ObjCPreciseLifetime: - handleObjCPreciseLifetimeAttr(S, D, Attr); break; + handleObjCPreciseLifetimeAttr(S, D, Attr); + break; case AttributeList::AT_ObjCReturnsInnerPointer: - handleObjCReturnsInnerPointerAttr(S, D, Attr); break; + handleObjCReturnsInnerPointerAttr(S, D, Attr); + break; case AttributeList::AT_ObjCRequiresSuper: - handleObjCRequiresSuperAttr(S, D, Attr); break; - - case AttributeList::AT_NSBridged: - handleNSBridgedAttr(S, scope, D, Attr); break; - + handleObjCRequiresSuperAttr(S, D, Attr); + break; + case AttributeList::AT_ObjCBridge: - handleObjCBridgeAttr(S, scope, D, Attr); break; + handleObjCBridgeAttr(S, scope, D, Attr); + break; + + case AttributeList::AT_ObjCBridgeMutable: + handleObjCBridgeMutableAttr(S, scope, D, Attr); + break; + + case AttributeList::AT_ObjCBridgeRelated: + handleObjCBridgeRelatedAttr(S, scope, D, Attr); + break; + case AttributeList::AT_ObjCDesignatedInitializer: + handleObjCDesignatedInitializer(S, D, Attr); + break; + + case AttributeList::AT_ObjCRuntimeName: + handleObjCRuntimeName(S, D, Attr); + break; + case AttributeList::AT_CFAuditedTransfer: + handleCFAuditedTransferAttr(S, D, Attr); + break; case AttributeList::AT_CFUnknownTransfer: - handleCFTransferAttr(S, D, Attr); break; + handleCFUnknownTransferAttr(S, D, Attr); + break; - // Checker-specific. case AttributeList::AT_CFConsumed: - case AttributeList::AT_NSConsumed: handleNSConsumedAttr (S, D, Attr); break; + case AttributeList::AT_NSConsumed: + handleNSConsumedAttr(S, D, Attr); + break; case AttributeList::AT_NSConsumesSelf: - handleNSConsumesSelfAttr(S, D, Attr); break; + handleSimpleAttribute<NSConsumesSelfAttr>(S, D, Attr); + break; case AttributeList::AT_NSReturnsAutoreleased: case AttributeList::AT_NSReturnsNotRetained: case AttributeList::AT_CFReturnsNotRetained: case AttributeList::AT_NSReturnsRetained: case AttributeList::AT_CFReturnsRetained: - handleNSReturnsRetainedAttr(S, D, Attr); break; - + handleNSReturnsRetainedAttr(S, D, Attr); + break; case AttributeList::AT_WorkGroupSizeHint: + handleWorkGroupSize<WorkGroupSizeHintAttr>(S, D, Attr); + break; case AttributeList::AT_ReqdWorkGroupSize: - handleWorkGroupSize(S, D, Attr); break; - + handleWorkGroupSize<ReqdWorkGroupSizeAttr>(S, D, Attr); + break; case AttributeList::AT_VecTypeHint: - handleVecTypeHint(S, D, Attr); break; + handleVecTypeHint(S, D, Attr); + break; - case AttributeList::AT_InitPriority: - handleInitPriorityAttr(S, D, Attr); break; - - case AttributeList::AT_Packed: handlePackedAttr (S, D, Attr); break; - case AttributeList::AT_Section: handleSectionAttr (S, D, Attr); break; + case AttributeList::AT_InitPriority: + handleInitPriorityAttr(S, D, Attr); + break; + + case AttributeList::AT_Packed: + handlePackedAttr(S, D, Attr); + break; + case AttributeList::AT_Section: + handleSectionAttr(S, D, Attr); + break; case AttributeList::AT_Unavailable: handleAttrWithMessage<UnavailableAttr>(S, D, Attr); break; - case AttributeList::AT_ArcWeakrefUnavailable: - handleArcWeakrefUnavailableAttr (S, D, Attr); + case AttributeList::AT_ArcWeakrefUnavailable: + handleSimpleAttribute<ArcWeakrefUnavailableAttr>(S, D, Attr); break; case AttributeList::AT_ObjCRootClass: - handleObjCRootClassAttr(S, D, Attr); + handleSimpleAttribute<ObjCRootClassAttr>(S, D, Attr); break; - case AttributeList::AT_ObjCRequiresPropertyDefs: - handleObjCRequiresPropertyDefsAttr (S, D, Attr); + case AttributeList::AT_ObjCExplicitProtocolImpl: + handleObjCSuppresProtocolAttr(S, D, Attr); + break; + case AttributeList::AT_ObjCRequiresPropertyDefs: + handleSimpleAttribute<ObjCRequiresPropertyDefsAttr>(S, D, Attr); + break; + case AttributeList::AT_Unused: + handleSimpleAttribute<UnusedAttr>(S, D, Attr); break; - case AttributeList::AT_Unused: handleUnusedAttr (S, D, Attr); break; case AttributeList::AT_ReturnsTwice: - handleReturnsTwiceAttr(S, D, Attr); + handleSimpleAttribute<ReturnsTwiceAttr>(S, D, Attr); + break; + case AttributeList::AT_Used: + handleUsedAttr(S, D, Attr); break; - case AttributeList::AT_Used: handleUsedAttr (S, D, Attr); break; case AttributeList::AT_Visibility: handleVisibilityAttr(S, D, Attr, false); break; @@ -4759,36 +4334,58 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handleVisibilityAttr(S, D, Attr, true); break; case AttributeList::AT_WarnUnused: - handleWarnUnusedAttr(S, D, Attr); + handleSimpleAttribute<WarnUnusedAttr>(S, D, Attr); + break; + case AttributeList::AT_WarnUnusedResult: + handleWarnUnusedResult(S, D, Attr); + break; + case AttributeList::AT_Weak: + handleSimpleAttribute<WeakAttr>(S, D, Attr); break; - case AttributeList::AT_WarnUnusedResult: handleWarnUnusedResult(S, D, Attr); + case AttributeList::AT_WeakRef: + handleWeakRefAttr(S, D, Attr); + break; + case AttributeList::AT_WeakImport: + handleWeakImportAttr(S, D, Attr); break; - case AttributeList::AT_Weak: handleWeakAttr (S, D, Attr); break; - case AttributeList::AT_WeakRef: handleWeakRefAttr (S, D, Attr); break; - case AttributeList::AT_WeakImport: handleWeakImportAttr (S, D, Attr); break; case AttributeList::AT_TransparentUnion: handleTransparentUnionAttr(S, D, Attr); break; case AttributeList::AT_ObjCException: - handleObjCExceptionAttr(S, D, Attr); + handleSimpleAttribute<ObjCExceptionAttr>(S, D, Attr); break; case AttributeList::AT_ObjCMethodFamily: handleObjCMethodFamilyAttr(S, D, Attr); break; - case AttributeList::AT_ObjCNSObject:handleObjCNSObject (S, D, Attr); break; - case AttributeList::AT_Blocks: handleBlocksAttr (S, D, Attr); break; - case AttributeList::AT_Sentinel: handleSentinelAttr (S, D, Attr); break; - case AttributeList::AT_Const: handleConstAttr (S, D, Attr); break; - case AttributeList::AT_Pure: handlePureAttr (S, D, Attr); break; - case AttributeList::AT_Cleanup: handleCleanupAttr (S, D, Attr); break; - case AttributeList::AT_NoDebug: handleNoDebugAttr (S, D, Attr); break; - case AttributeList::AT_NoInline: handleNoInlineAttr (S, D, Attr); break; - case AttributeList::AT_Regparm: handleRegparmAttr (S, D, Attr); break; - case AttributeList::IgnoredAttribute: - // Just ignore - break; - case AttributeList::AT_NoInstrumentFunction: // Interacts with -pg. - handleNoInstrumentFunctionAttr(S, D, Attr); + case AttributeList::AT_ObjCNSObject: + handleObjCNSObject(S, D, Attr); + break; + case AttributeList::AT_Blocks: + handleBlocksAttr(S, D, Attr); + break; + case AttributeList::AT_Sentinel: + handleSentinelAttr(S, D, Attr); + break; + case AttributeList::AT_Const: + handleSimpleAttribute<ConstAttr>(S, D, Attr); + break; + case AttributeList::AT_Pure: + handleSimpleAttribute<PureAttr>(S, D, Attr); + break; + case AttributeList::AT_Cleanup: + handleCleanupAttr(S, D, Attr); + break; + case AttributeList::AT_NoDebug: + handleNoDebugAttr(S, D, Attr); + break; + case AttributeList::AT_NoDuplicate: + handleSimpleAttribute<NoDuplicateAttr>(S, D, Attr); + break; + case AttributeList::AT_NoInline: + handleSimpleAttribute<NoInlineAttr>(S, D, Attr); + break; + case AttributeList::AT_NoInstrumentFunction: // Interacts with -pg. + handleSimpleAttribute<NoInstrumentFunctionAttr>(S, D, Attr); break; case AttributeList::AT_StdCall: case AttributeList::AT_CDecl: @@ -4803,32 +4400,27 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handleCallConvAttr(S, D, Attr); break; case AttributeList::AT_OpenCLKernel: - handleOpenCLKernelAttr(S, D, Attr); + handleSimpleAttribute<OpenCLKernelAttr>(S, D, Attr); break; case AttributeList::AT_OpenCLImageAccess: - handleOpenCLImageAccessAttr(S, D, Attr); + handleSimpleAttribute<OpenCLImageAccessAttr>(S, D, Attr); break; // Microsoft attributes: case AttributeList::AT_MsStruct: - handleMsStructAttr(S, D, Attr); + handleSimpleAttribute<MsStructAttr>(S, D, Attr); break; case AttributeList::AT_Uuid: handleUuidAttr(S, D, Attr); break; - case AttributeList::AT_SingleInheritance: - case AttributeList::AT_MultipleInheritance: - case AttributeList::AT_VirtualInheritance: - handleInheritanceAttr(S, D, Attr); - break; - case AttributeList::AT_Win64: - handlePortabilityAttr(S, D, Attr); - break; - case AttributeList::AT_ForceInline: - handleForceInlineAttr(S, D, Attr); + case AttributeList::AT_MSInheritance: + handleMSInheritanceAttr(S, D, Attr); break; case AttributeList::AT_SelectAny: - handleSelectAnyAttr(S, D, Attr); + handleSimpleAttribute<SelectAnyAttr>(S, D, Attr); + break; + case AttributeList::AT_Thread: + handleDeclspecThreadAttr(S, D, Attr); break; // Thread safety attributes: @@ -4839,28 +4431,25 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handleAssertSharedLockAttr(S, D, Attr); break; case AttributeList::AT_GuardedVar: - handleGuardedVarAttr(S, D, Attr); + handleSimpleAttribute<GuardedVarAttr>(S, D, Attr); break; case AttributeList::AT_PtGuardedVar: handlePtGuardedVarAttr(S, D, Attr); break; case AttributeList::AT_ScopedLockable: - handleScopedLockableAttr(S, D, Attr); + handleSimpleAttribute<ScopedLockableAttr>(S, D, Attr); break; case AttributeList::AT_NoSanitizeAddress: - handleNoSanitizeAddressAttr(S, D, Attr); + handleSimpleAttribute<NoSanitizeAddressAttr>(S, D, Attr); break; case AttributeList::AT_NoThreadSafetyAnalysis: - handleNoThreadSafetyAnalysis(S, D, Attr); + handleSimpleAttribute<NoThreadSafetyAnalysisAttr>(S, D, Attr); break; case AttributeList::AT_NoSanitizeThread: - handleNoSanitizeThread(S, D, Attr); + handleSimpleAttribute<NoSanitizeThreadAttr>(S, D, Attr); break; case AttributeList::AT_NoSanitizeMemory: - handleNoSanitizeMemory(S, D, Attr); - break; - case AttributeList::AT_Lockable: - handleLockableAttr(S, D, Attr); + handleSimpleAttribute<NoSanitizeMemoryAttr>(S, D, Attr); break; case AttributeList::AT_GuardedBy: handleGuardedByAttr(S, D, Attr); @@ -4868,12 +4457,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_PtGuardedBy: handlePtGuardedByAttr(S, D, Attr); break; - case AttributeList::AT_ExclusiveLockFunction: - handleExclusiveLockFunctionAttr(S, D, Attr); - break; - case AttributeList::AT_ExclusiveLocksRequired: - handleExclusiveLocksRequiredAttr(S, D, Attr); - break; case AttributeList::AT_ExclusiveTrylockFunction: handleExclusiveTrylockFunctionAttr(S, D, Attr); break; @@ -4883,18 +4466,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_LocksExcluded: handleLocksExcludedAttr(S, D, Attr); break; - case AttributeList::AT_SharedLockFunction: - handleSharedLockFunctionAttr(S, D, Attr); - break; - case AttributeList::AT_SharedLocksRequired: - handleSharedLocksRequiredAttr(S, D, Attr); - break; case AttributeList::AT_SharedTrylockFunction: handleSharedTrylockFunctionAttr(S, D, Attr); break; - case AttributeList::AT_UnlockFunction: - handleUnlockFunAttr(S, D, Attr); - break; case AttributeList::AT_AcquiredBefore: handleAcquiredBeforeAttr(S, D, Attr); break; @@ -4902,10 +4476,38 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handleAcquiredAfterAttr(S, D, Attr); break; + // Capability analysis attributes. + case AttributeList::AT_Capability: + case AttributeList::AT_Lockable: + handleCapabilityAttr(S, D, Attr); + break; + case AttributeList::AT_RequiresCapability: + handleRequiresCapabilityAttr(S, D, Attr); + break; + + case AttributeList::AT_AssertCapability: + handleAssertCapabilityAttr(S, D, Attr); + break; + case AttributeList::AT_AcquireCapability: + handleAcquireCapabilityAttr(S, D, Attr); + break; + case AttributeList::AT_ReleaseCapability: + handleReleaseCapabilityAttr(S, D, Attr); + break; + case AttributeList::AT_TryAcquireCapability: + handleTryAcquireCapabilityAttr(S, D, Attr); + break; + // Consumed analysis attributes. case AttributeList::AT_Consumable: handleConsumableAttr(S, D, Attr); break; + case AttributeList::AT_ConsumableAutoCast: + handleSimpleAttribute<ConsumableAutoCastAttr>(S, D, Attr); + break; + case AttributeList::AT_ConsumableSetOnRead: + handleSimpleAttribute<ConsumableSetOnReadAttr>(S, D, Attr); + break; case AttributeList::AT_CallableWhen: handleCallableWhenAttr(S, D, Attr); break; @@ -4929,15 +4531,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_TypeTagForDatatype: handleTypeTagForDatatypeAttr(S, D, Attr); break; - - default: - // Ask target about the attribute. - const TargetAttributesSema &TargetAttrs = S.getTargetAttributesSema(); - if (!TargetAttrs.ProcessDeclAttribute(scope, D, Attr, S)) - S.Diag(Attr.getLoc(), Attr.isDeclspecAttribute() ? - diag::warn_unhandled_ms_attribute_ignored : - diag::warn_unknown_attribute_ignored) << Attr.getName(); - break; } } @@ -4949,15 +4542,32 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, for (const AttributeList* l = AttrList; l; l = l->getNext()) ProcessDeclAttribute(*this, S, D, *l, IncludeCXX11Attributes); + // FIXME: We should be able to handle these cases in TableGen. // GCC accepts // static int a9 __attribute__((weakref)); // but that looks really pointless. We reject it. if (D->hasAttr<WeakRefAttr>() && !D->hasAttr<AliasAttr>()) { - Diag(AttrList->getLoc(), diag::err_attribute_weakref_without_alias) << - cast<NamedDecl>(D)->getNameAsString(); + Diag(AttrList->getLoc(), diag::err_attribute_weakref_without_alias) + << cast<NamedDecl>(D); D->dropAttr<WeakRefAttr>(); return; } + + if (!D->hasAttr<OpenCLKernelAttr>()) { + // These attributes cannot be applied to a non-kernel function. + if (Attr *A = D->getAttr<ReqdWorkGroupSizeAttr>()) { + Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A; + D->setInvalidDecl(); + } + if (Attr *A = D->getAttr<WorkGroupSizeHintAttr>()) { + Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A; + D->setInvalidDecl(); + } + if (Attr *A = D->getAttr<VecTypeHintAttr>()) { + Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A; + D->setInvalidDecl(); + } + } } // Annotation attributes are the only attributes allowed after an access @@ -5009,7 +4619,7 @@ void Sema::checkUnusedDeclAttributes(Declarator &D) { NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II, SourceLocation Loc) { assert(isa<FunctionDecl>(ND) || isa<VarDecl>(ND)); - NamedDecl *NewD = 0; + NamedDecl *NewD = nullptr; if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { FunctionDecl *NewFD; // FIXME: Missing call to CheckFunctionDeclaration(). @@ -5032,9 +4642,8 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II, QualType FDTy = FD->getType(); if (const FunctionProtoType *FT = FDTy->getAs<FunctionProtoType>()) { SmallVector<ParmVarDecl*, 16> Params; - for (FunctionProtoType::arg_type_iterator AI = FT->arg_type_begin(), - AE = FT->arg_type_end(); AI != AE; ++AI) { - ParmVarDecl *Param = BuildParmVarDeclForTypedef(NewFD, Loc, *AI); + for (const auto &AI : FT->param_types()) { + ParmVarDecl *Param = BuildParmVarDeclForTypedef(NewFD, Loc, AI); Param->setScopeInfo(0, Params.size()); Params.push_back(Param); } @@ -5061,18 +4670,20 @@ void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) { if (W.getAlias()) { // clone decl, impersonate __attribute(weak,alias(...)) IdentifierInfo *NDId = ND->getIdentifier(); NamedDecl *NewD = DeclClonePragmaWeak(ND, W.getAlias(), W.getLocation()); - NewD->addAttr(::new (Context) AliasAttr(W.getLocation(), Context, - NDId->getName())); - NewD->addAttr(::new (Context) WeakAttr(W.getLocation(), Context)); + NewD->addAttr(AliasAttr::CreateImplicit(Context, NDId->getName(), + W.getLocation())); + NewD->addAttr(WeakAttr::CreateImplicit(Context, W.getLocation())); WeakTopLevelDecl.push_back(NewD); // FIXME: "hideous" code from Sema::LazilyCreateBuiltin // to insert Decl at TU scope, sorry. DeclContext *SavedContext = CurContext; CurContext = Context.getTranslationUnitDecl(); + NewD->setDeclContext(CurContext); + NewD->setLexicalDeclContext(CurContext); PushOnScopeChains(NewD, S); CurContext = SavedContext; } else { // just add weak to existing - ND->addAttr(::new (Context) WeakAttr(W.getLocation(), Context)); + ND->addAttr(WeakAttr::CreateImplicit(Context, W.getLocation())); } } @@ -5081,7 +4692,7 @@ void Sema::ProcessPragmaWeak(Scope *S, Decl *D) { // have to do this. LoadExternalWeakUndeclaredIdentifiers(); if (!WeakUndeclaredIdentifiers.empty()) { - NamedDecl *ND = NULL; + NamedDecl *ND = nullptr; if (VarDecl *VD = dyn_cast<VarDecl>(D)) if (VD->isExternC()) ND = VD; @@ -5141,8 +4752,9 @@ static bool isForbiddenTypeAllowed(Sema &S, Decl *decl) { static void handleDelayedForbiddenType(Sema &S, DelayedDiagnostic &diag, Decl *decl) { if (decl && isForbiddenTypeAllowed(S, decl)) { - decl->addAttr(new (S.Context) UnavailableAttr(diag.Loc, S.Context, - "this system declaration uses an unsupported type")); + decl->addAttr(UnavailableAttr::CreateImplicit(S.Context, + "this system declaration uses an unsupported type", + diag.Loc)); return; } if (S.getLangOpts().ObjCAutoRefCount) @@ -5190,9 +4802,11 @@ void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) { switch (diag.Kind) { case DelayedDiagnostic::Deprecation: - // Don't bother giving deprecation diagnostics if the decl is invalid. + case DelayedDiagnostic::Unavailable: + // Don't bother giving deprecation/unavailable diagnostics if + // the decl is invalid. if (!decl->isInvalidDecl()) - HandleDelayedDeprecationCheck(diag, decl); + HandleDelayedAvailabilityCheck(diag, decl); break; case DelayedDiagnostic::Access: @@ -5227,61 +4841,125 @@ static bool isDeclDeprecated(Decl *D) { return false; } +static bool isDeclUnavailable(Decl *D) { + do { + if (D->isUnavailable()) + return true; + // A category implicitly has the availability of the interface. + if (const ObjCCategoryDecl *CatD = dyn_cast<ObjCCategoryDecl>(D)) + return CatD->getClassInterface()->isUnavailable(); + } while ((D = cast_or_null<Decl>(D->getDeclContext()))); + return false; +} + static void -DoEmitDeprecationWarning(Sema &S, const NamedDecl *D, StringRef Message, - SourceLocation Loc, - const ObjCInterfaceDecl *UnknownObjCClass, - const ObjCPropertyDecl *ObjCPropery) { +DoEmitAvailabilityWarning(Sema &S, + DelayedDiagnostic::DDKind K, + Decl *Ctx, + const NamedDecl *D, + StringRef Message, + SourceLocation Loc, + const ObjCInterfaceDecl *UnknownObjCClass, + const ObjCPropertyDecl *ObjCProperty, + bool ObjCPropertyAccess) { + + // Diagnostics for deprecated or unavailable. + unsigned diag, diag_message, diag_fwdclass_message; + + // Matches 'diag::note_property_attribute' options. + unsigned property_note_select; + + // Matches diag::note_availability_specified_here. + unsigned available_here_select_kind; + + // Don't warn if our current context is deprecated or unavailable. + switch (K) { + case DelayedDiagnostic::Deprecation: + if (isDeclDeprecated(Ctx)) + return; + diag = !ObjCPropertyAccess ? diag::warn_deprecated + : diag::warn_property_method_deprecated; + diag_message = diag::warn_deprecated_message; + diag_fwdclass_message = diag::warn_deprecated_fwdclass_message; + property_note_select = /* deprecated */ 0; + available_here_select_kind = /* deprecated */ 2; + break; + + case DelayedDiagnostic::Unavailable: + if (isDeclUnavailable(Ctx)) + return; + diag = !ObjCPropertyAccess ? diag::err_unavailable + : diag::err_property_method_unavailable; + diag_message = diag::err_unavailable_message; + diag_fwdclass_message = diag::warn_unavailable_fwdclass_message; + property_note_select = /* unavailable */ 1; + available_here_select_kind = /* unavailable */ 0; + break; + + default: + llvm_unreachable("Neither a deprecation or unavailable kind"); + } + DeclarationName Name = D->getDeclName(); if (!Message.empty()) { - S.Diag(Loc, diag::warn_deprecated_message) << Name << Message; - S.Diag(D->getLocation(), - isa<ObjCMethodDecl>(D) ? diag::note_method_declared_at - : diag::note_previous_decl) << Name; - if (ObjCPropery) - S.Diag(ObjCPropery->getLocation(), diag::note_property_attribute) - << ObjCPropery->getDeclName() << 0; + S.Diag(Loc, diag_message) << Name << Message; + if (ObjCProperty) + S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute) + << ObjCProperty->getDeclName() << property_note_select; } else if (!UnknownObjCClass) { - S.Diag(Loc, diag::warn_deprecated) << D->getDeclName(); - S.Diag(D->getLocation(), - isa<ObjCMethodDecl>(D) ? diag::note_method_declared_at - : diag::note_previous_decl) << Name; - if (ObjCPropery) - S.Diag(ObjCPropery->getLocation(), diag::note_property_attribute) - << ObjCPropery->getDeclName() << 0; + S.Diag(Loc, diag) << Name; + if (ObjCProperty) + S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute) + << ObjCProperty->getDeclName() << property_note_select; } else { - S.Diag(Loc, diag::warn_deprecated_fwdclass_message) << Name; + S.Diag(Loc, diag_fwdclass_message) << Name; S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class); } -} -void Sema::HandleDelayedDeprecationCheck(DelayedDiagnostic &DD, - Decl *Ctx) { - if (isDeclDeprecated(Ctx)) - return; - - DD.Triggered = true; - DoEmitDeprecationWarning(*this, DD.getDeprecationDecl(), - DD.getDeprecationMessage(), DD.Loc, - DD.getUnknownObjCClass(), - DD.getObjCProperty()); + S.Diag(D->getLocation(), diag::note_availability_specified_here) + << D << available_here_select_kind; } -void Sema::EmitDeprecationWarning(NamedDecl *D, StringRef Message, - SourceLocation Loc, - const ObjCInterfaceDecl *UnknownObjCClass, - const ObjCPropertyDecl *ObjCProperty) { +void Sema::HandleDelayedAvailabilityCheck(DelayedDiagnostic &DD, + Decl *Ctx) { + DD.Triggered = true; + DoEmitAvailabilityWarning(*this, + (DelayedDiagnostic::DDKind) DD.Kind, + Ctx, + DD.getDeprecationDecl(), + DD.getDeprecationMessage(), + DD.Loc, + DD.getUnknownObjCClass(), + DD.getObjCProperty(), false); +} + +void Sema::EmitAvailabilityWarning(AvailabilityDiagnostic AD, + NamedDecl *D, StringRef Message, + SourceLocation Loc, + const ObjCInterfaceDecl *UnknownObjCClass, + const ObjCPropertyDecl *ObjCProperty, + bool ObjCPropertyAccess) { // Delay if we're currently parsing a declaration. if (DelayedDiagnostics.shouldDelayDiagnostics()) { - DelayedDiagnostics.add(DelayedDiagnostic::makeDeprecation(Loc, D, - UnknownObjCClass, - ObjCProperty, - Message)); + DelayedDiagnostics.add(DelayedDiagnostic::makeAvailability(AD, Loc, D, + UnknownObjCClass, + ObjCProperty, + Message, + ObjCPropertyAccess)); return; } - // Otherwise, don't warn if our current context is deprecated. - if (isDeclDeprecated(cast<Decl>(getCurLexicalContext()))) - return; - DoEmitDeprecationWarning(*this, D, Message, Loc, UnknownObjCClass, ObjCProperty); + Decl *Ctx = cast<Decl>(getCurLexicalContext()); + DelayedDiagnostic::DDKind K; + switch (AD) { + case AD_Deprecation: + K = DelayedDiagnostic::Deprecation; + break; + case AD_Unavailable: + K = DelayedDiagnostic::Unavailable; + break; + } + + DoEmitAvailabilityWarning(*this, K, Ctx, D, Message, Loc, + UnknownObjCClass, ObjCProperty, ObjCPropertyAccess); } |