diff options
Diffstat (limited to 'lib/Sema/SemaDeclAttr.cpp')
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 1214 |
1 files changed, 799 insertions, 415 deletions
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 77deed6047f4..0e10804a2ec7 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -93,6 +93,17 @@ static unsigned getFunctionOrMethodNumParams(const Decl *D) { return cast<ObjCMethodDecl>(D)->param_size(); } +static const ParmVarDecl *getFunctionOrMethodParam(const Decl *D, + unsigned Idx) { + if (const auto *FD = dyn_cast<FunctionDecl>(D)) + return FD->getParamDecl(Idx); + if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) + return MD->getParamDecl(Idx); + if (const auto *BD = dyn_cast<BlockDecl>(D)) + return BD->getParamDecl(Idx); + return nullptr; +} + static QualType getFunctionOrMethodParamType(const Decl *D, unsigned Idx) { if (const FunctionType *FnTy = D->getFunctionType()) return cast<FunctionProtoType>(FnTy)->getParamType(Idx); @@ -103,12 +114,8 @@ static QualType getFunctionOrMethodParamType(const Decl *D, unsigned Idx) { } static SourceRange getFunctionOrMethodParamRange(const Decl *D, unsigned Idx) { - if (const auto *FD = dyn_cast<FunctionDecl>(D)) - return FD->getParamDecl(Idx)->getSourceRange(); - if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) - return MD->parameters()[Idx]->getSourceRange(); - if (const auto *BD = dyn_cast<BlockDecl>(D)) - return BD->getParamDecl(Idx)->getSourceRange(); + if (auto *PVD = getFunctionOrMethodParam(D, Idx)) + return PVD->getSourceRange(); return SourceRange(); } @@ -182,7 +189,7 @@ static bool checkAttributeNumArgsImpl(Sema &S, const ParsedAttr &AL, unsigned Num, unsigned Diag, Compare Comp) { if (Comp(getNumAttributeArgs(AL), Num)) { - S.Diag(AL.getLoc(), Diag) << AL.getName() << Num; + S.Diag(AL.getLoc(), Diag) << AL << Num; return false; } @@ -225,34 +232,25 @@ getAttrLoc(const AttrInfo &AL) { } static SourceLocation getAttrLoc(const ParsedAttr &AL) { return AL.getLoc(); } -/// A helper function to provide Attribute Name for the Attr types -/// AND the ParsedAttr. -template <typename AttrInfo> -static typename std::enable_if<std::is_base_of<Attr, AttrInfo>::value, - const AttrInfo *>::type -getAttrName(const AttrInfo &AL) { - return &AL; -} -static const IdentifierInfo *getAttrName(const ParsedAttr &AL) { - return AL.getName(); -} - /// If Expr is a valid integer constant, get the value of the integer /// expression and return success or failure. May output an error. +/// +/// Negative argument is implicitly converted to unsigned, unless +/// \p StrictlyUnsigned is true. template <typename AttrInfo> static bool checkUInt32Argument(Sema &S, const AttrInfo &AI, const Expr *Expr, - uint32_t &Val, unsigned Idx = UINT_MAX) { + uint32_t &Val, unsigned Idx = UINT_MAX, + bool StrictlyUnsigned = false) { llvm::APSInt I(32); if (Expr->isTypeDependent() || Expr->isValueDependent() || !Expr->isIntegerConstantExpr(I, S.Context)) { if (Idx != UINT_MAX) S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type) - << getAttrName(AI) << Idx << AANT_ArgumentIntegerConstant - << Expr->getSourceRange(); + << AI << Idx << AANT_ArgumentIntegerConstant + << Expr->getSourceRange(); else S.Diag(getAttrLoc(AI), diag::err_attribute_argument_type) - << getAttrName(AI) << AANT_ArgumentIntegerConstant - << Expr->getSourceRange(); + << AI << AANT_ArgumentIntegerConstant << Expr->getSourceRange(); return false; } @@ -262,6 +260,12 @@ static bool checkUInt32Argument(Sema &S, const AttrInfo &AI, const Expr *Expr, return false; } + if (StrictlyUnsigned && I.isSigned() && I.isNegative()) { + S.Diag(getAttrLoc(AI), diag::err_attribute_requires_positive_integer) + << AI << /*non-negative*/ 1; + return false; + } + Val = (uint32_t)I.getZExtValue(); return true; } @@ -291,10 +295,19 @@ static bool checkPositiveIntArgument(Sema &S, const AttrInfo &AI, const Expr *Ex /// Diagnose mutually exclusive attributes when present on a given /// declaration. Returns true if diagnosed. template <typename AttrTy> -static bool checkAttrMutualExclusion(Sema &S, Decl *D, SourceRange Range, - IdentifierInfo *Ident) { +static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { if (const auto *A = D->getAttr<AttrTy>()) { - S.Diag(Range.getBegin(), diag::err_attributes_are_not_compatible) << Ident + S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << A; + S.Diag(A->getLocation(), diag::note_conflicting_attribute); + return true; + } + return false; +} + +template <typename AttrTy> +static bool checkAttrMutualExclusion(Sema &S, Decl *D, const Attr &AL) { + if (const auto *A = D->getAttr<AttrTy>()) { + S.Diag(AL.getLocation(), diag::err_attributes_are_not_compatible) << &AL << A; S.Diag(A->getLocation(), diag::note_conflicting_attribute); return true; @@ -324,22 +337,21 @@ static bool checkFunctionOrMethodParameterIndex( if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() || !IdxExpr->isIntegerConstantExpr(IdxInt, S.Context)) { S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type) - << getAttrName(AI) << AttrArgNum << AANT_ArgumentIntegerConstant - << IdxExpr->getSourceRange(); + << &AI << AttrArgNum << AANT_ArgumentIntegerConstant + << IdxExpr->getSourceRange(); return false; } unsigned IdxSource = IdxInt.getLimitedValue(UINT_MAX); if (IdxSource < 1 || (!IV && IdxSource > NumParams)) { S.Diag(getAttrLoc(AI), diag::err_attribute_argument_out_of_bounds) - << getAttrName(AI) << AttrArgNum << IdxExpr->getSourceRange(); + << &AI << AttrArgNum << IdxExpr->getSourceRange(); return false; } if (HasImplicitThisParam && !CanIndexImplicitThis) { if (IdxSource == 1) { - S.Diag(getAttrLoc(AI), - diag::err_attribute_invalid_implicit_this_argument) - << getAttrName(AI) << IdxExpr->getSourceRange(); + S.Diag(getAttrLoc(AI), diag::err_attribute_invalid_implicit_this_argument) + << &AI << IdxExpr->getSourceRange(); return false; } } @@ -359,7 +371,7 @@ bool Sema::checkStringLiteralArgumentAttr(const ParsedAttr &AL, unsigned ArgNum, if (AL.isArgIdent(ArgNum)) { IdentifierLoc *Loc = AL.getArgAsIdent(ArgNum); Diag(Loc->Loc, diag::err_attribute_argument_type) - << AL.getName() << AANT_ArgumentString + << AL << AANT_ArgumentString << FixItHint::CreateInsertion(Loc->Loc, "\"") << FixItHint::CreateInsertion(getLocForEndOfToken(Loc->Loc), "\""); Str = Loc->Ident->getName(); @@ -372,11 +384,11 @@ bool Sema::checkStringLiteralArgumentAttr(const ParsedAttr &AL, unsigned ArgNum, Expr *ArgExpr = AL.getArgAsExpr(ArgNum); const auto *Literal = dyn_cast<StringLiteral>(ArgExpr->IgnoreParenCasts()); if (ArgLocation) - *ArgLocation = ArgExpr->getLocStart(); + *ArgLocation = ArgExpr->getBeginLoc(); if (!Literal || !Literal->isAscii()) { - Diag(ArgExpr->getLocStart(), diag::err_attribute_argument_type) - << AL.getName() << AANT_ArgumentString; + Diag(ArgExpr->getBeginLoc(), diag::err_attribute_argument_type) + << AL << AANT_ArgumentString; return false; } @@ -387,9 +399,59 @@ bool Sema::checkStringLiteralArgumentAttr(const ParsedAttr &AL, unsigned ArgNum, /// Applies the given attribute to the Decl without performing any /// additional semantic checking. template <typename AttrType> +static void handleSimpleAttribute(Sema &S, Decl *D, SourceRange SR, + unsigned SpellingIndex) { + D->addAttr(::new (S.Context) AttrType(SR, S.Context, SpellingIndex)); +} + +template <typename AttrType> static void handleSimpleAttribute(Sema &S, Decl *D, const ParsedAttr &AL) { - D->addAttr(::new (S.Context) AttrType(AL.getRange(), S.Context, - AL.getAttributeSpellingListIndex())); + handleSimpleAttribute<AttrType>(S, D, AL.getRange(), + AL.getAttributeSpellingListIndex()); +} + + +template <typename... DiagnosticArgs> +static const Sema::SemaDiagnosticBuilder& +appendDiagnostics(const Sema::SemaDiagnosticBuilder &Bldr) { + return Bldr; +} + +template <typename T, typename... DiagnosticArgs> +static const Sema::SemaDiagnosticBuilder& +appendDiagnostics(const Sema::SemaDiagnosticBuilder &Bldr, T &&ExtraArg, + DiagnosticArgs &&... ExtraArgs) { + return appendDiagnostics(Bldr << std::forward<T>(ExtraArg), + std::forward<DiagnosticArgs>(ExtraArgs)...); +} + +/// Add an attribute {@code AttrType} to declaration {@code D}, provided that +/// {@code PassesCheck} is true. +/// Otherwise, emit diagnostic {@code DiagID}, passing in all parameters +/// specified in {@code ExtraArgs}. +template <typename AttrType, typename... DiagnosticArgs> +static void +handleSimpleAttributeOrDiagnose(Sema &S, Decl *D, SourceRange SR, + unsigned SpellingIndex, + bool PassesCheck, + unsigned DiagID, DiagnosticArgs&&... ExtraArgs) { + if (!PassesCheck) { + Sema::SemaDiagnosticBuilder DB = S.Diag(D->getBeginLoc(), DiagID); + appendDiagnostics(DB, std::forward<DiagnosticArgs>(ExtraArgs)...); + return; + } + handleSimpleAttribute<AttrType>(S, D, SR, SpellingIndex); +} + +template <typename AttrType, typename... DiagnosticArgs> +static void +handleSimpleAttributeOrDiagnose(Sema &S, Decl *D, const ParsedAttr &AL, + bool PassesCheck, + unsigned DiagID, + DiagnosticArgs&&... ExtraArgs) { + return handleSimpleAttributeOrDiagnose<AttrType>( + S, D, AL.getRange(), AL.getAttributeSpellingListIndex(), PassesCheck, + DiagID, std::forward<DiagnosticArgs>(ExtraArgs)...); } template <typename AttrType> @@ -404,8 +466,7 @@ template <typename AttrType, typename IncompatibleAttrType, typename... IncompatibleAttrTypes> static void handleSimpleAttributeWithExclusions(Sema &S, Decl *D, const ParsedAttr &AL) { - if (checkAttrMutualExclusion<IncompatibleAttrType>(S, D, AL.getRange(), - AL.getName())) + if (checkAttrMutualExclusion<IncompatibleAttrType>(S, D, AL)) return; handleSimpleAttributeWithExclusions<AttrType, IncompatibleAttrTypes...>(S, D, AL); @@ -421,17 +482,36 @@ static bool isIntOrBool(Expr *Exp) { // Check to see if the type is a smart pointer of some kind. We assume // it's a smart pointer if it defines both operator-> and operator*. static bool threadSafetyCheckIsSmartPointer(Sema &S, const RecordType* RT) { - DeclContextLookupResult Res1 = RT->getDecl()->lookup( - S.Context.DeclarationNames.getCXXOperatorName(OO_Star)); - if (Res1.empty()) - return false; + auto IsOverloadedOperatorPresent = [&S](const RecordDecl *Record, + OverloadedOperatorKind Op) { + DeclContextLookupResult Result = + Record->lookup(S.Context.DeclarationNames.getCXXOperatorName(Op)); + return !Result.empty(); + }; + + const RecordDecl *Record = RT->getDecl(); + bool foundStarOperator = IsOverloadedOperatorPresent(Record, OO_Star); + bool foundArrowOperator = IsOverloadedOperatorPresent(Record, OO_Arrow); + if (foundStarOperator && foundArrowOperator) + return true; - DeclContextLookupResult Res2 = RT->getDecl()->lookup( - S.Context.DeclarationNames.getCXXOperatorName(OO_Arrow)); - if (Res2.empty()) + const CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(Record); + if (!CXXRecord) return false; - return true; + for (auto BaseSpecifier : CXXRecord->bases()) { + if (!foundStarOperator) + foundStarOperator = IsOverloadedOperatorPresent( + BaseSpecifier.getType()->getAsRecordDecl(), OO_Star); + if (!foundArrowOperator) + foundArrowOperator = IsOverloadedOperatorPresent( + BaseSpecifier.getType()->getAsRecordDecl(), OO_Arrow); + } + + if (foundStarOperator && foundArrowOperator) + return true; + + return false; } /// Check if passed in Decl is a pointer type. @@ -455,8 +535,7 @@ static bool threadSafetyCheckIsPointer(Sema &S, const Decl *D, return true; } - S.Diag(AL.getLoc(), diag::warn_thread_attribute_decl_not_pointer) - << AL.getName() << QT; + S.Diag(AL.getLoc(), diag::warn_thread_attribute_decl_not_pointer) << AL << QT; return false; } @@ -473,6 +552,29 @@ static const RecordType *getRecordType(QualType QT) { return nullptr; } +template <typename AttrType> +static bool checkRecordDeclForAttr(const RecordDecl *RD) { + // Check if the record itself has the attribute. + if (RD->hasAttr<AttrType>()) + return true; + + // Else check if any base classes have the attribute. + if (const auto *CRD = dyn_cast<CXXRecordDecl>(RD)) { + CXXBasePaths BPaths(false, false); + if (CRD->lookupInBases( + [](const CXXBaseSpecifier *BS, CXXBasePath &) { + const auto &Ty = *BS->getType(); + // If it's type-dependent, we assume it could have the attribute. + if (Ty.isDependentType()) + return true; + return Ty.getAs<RecordType>()->getDecl()->hasAttr<AttrType>(); + }, + BPaths, true)) + return true; + } + return false; +} + static bool checkRecordTypeForCapability(Sema &S, QualType Ty) { const RecordType *RT = getRecordType(Ty); @@ -488,21 +590,7 @@ static bool checkRecordTypeForCapability(Sema &S, QualType Ty) { if (threadSafetyCheckIsSmartPointer(S, RT)) return true; - // Check if the record itself has a capability. - RecordDecl *RD = RT->getDecl(); - if (RD->hasAttr<CapabilityAttr>()) - return true; - - // Else check if any base classes have a capability. - if (const auto *CRD = dyn_cast<CXXRecordDecl>(RD)) { - CXXBasePaths BPaths(false, false); - if (CRD->lookupInBases([](const CXXBaseSpecifier *BS, CXXBasePath &) { - const auto *Type = BS->getType()->getAs<RecordType>(); - return Type->getDecl()->hasAttr<CapabilityAttr>(); - }, BPaths)) - return true; - } - return false; + return checkRecordDeclForAttr<CapabilityAttr>(RT->getDecl()); } static bool checkTypedefTypeForCapability(QualType Ty) { @@ -560,8 +648,27 @@ static bool isCapabilityExpr(Sema &S, const Expr *Ex) { static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, const ParsedAttr &AL, SmallVectorImpl<Expr *> &Args, - int Sidx = 0, + unsigned Sidx = 0, bool ParamIdxOk = false) { + if (Sidx == AL.getNumArgs()) { + // If we don't have any capability arguments, the attribute implicitly + // refers to 'this'. So we need to make sure that 'this' exists, i.e. we're + // a non-static method, and that the class is a (scoped) capability. + const auto *MD = dyn_cast<const CXXMethodDecl>(D); + if (MD && !MD->isStatic()) { + const CXXRecordDecl *RD = MD->getParent(); + // FIXME -- need to check this again on template instantiation + if (!checkRecordDeclForAttr<CapabilityAttr>(RD) && + !checkRecordDeclForAttr<ScopedLockableAttr>(RD)) + S.Diag(AL.getLoc(), + diag::warn_thread_attribute_not_on_capability_member) + << AL << MD->getParent(); + } else { + S.Diag(AL.getLoc(), diag::warn_thread_attribute_not_on_non_static_member) + << AL; + } + } + for (unsigned Idx = Sidx; Idx < AL.getNumArgs(); ++Idx) { Expr *ArgExp = AL.getArgAsExpr(Idx); @@ -582,7 +689,7 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, // We allow constant strings to be used as a placeholder for expressions // that are not valid C++ syntax, but warn that they are ignored. - S.Diag(AL.getLoc(), diag::warn_thread_attribute_ignored) << AL.getName(); + S.Diag(AL.getLoc(), diag::warn_thread_attribute_ignored) << AL; Args.push_back(ArgExp); continue; } @@ -611,7 +718,7 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, uint64_t ParamIdxFromZero = ParamIdxFromOne - 1; if (!ArgValue.isStrictlyPositive() || ParamIdxFromOne > NumParams) { S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_range) - << AL.getName() << Idx + 1 << NumParams; + << AL << Idx + 1 << NumParams; continue; } ArgTy = FD->getParamDecl(ParamIdxFromZero)->getType(); @@ -624,7 +731,7 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, // boolean logic expression. Eg) requires_capability(A || B && !C) if (!typeHasCapability(S, ArgTy) && !isCapabilityExpr(S, ArgExp)) S.Diag(AL.getLoc(), diag::warn_thread_attribute_argument_not_lockable) - << AL.getName() << ArgTy; + << AL << ArgTy; Args.push_back(ArgExp); } @@ -686,8 +793,7 @@ static bool checkAcquireOrderAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL, // Check that this attribute only applies to lockable types. QualType QT = cast<ValueDecl>(D)->getType(); if (!QT->isDependentType() && !typeHasCapability(S, QT)) { - S.Diag(AL.getLoc(), diag::warn_thread_attribute_decl_not_lockable) - << AL.getName(); + S.Diag(AL.getLoc(), diag::warn_thread_attribute_decl_not_lockable) << AL; return false; } @@ -772,9 +878,9 @@ static bool checkParamIsIntegerType(Sema &S, const FunctionDecl *FD, const ParmVarDecl *Param = FD->getParamDecl(Idx.getASTIndex()); if (!Param->getType()->isIntegerType() && !Param->getType()->isCharType()) { - SourceLocation SrcLoc = AttrArg->getLocStart(); + SourceLocation SrcLoc = AttrArg->getBeginLoc(); S.Diag(SrcLoc, diag::err_attribute_integers_only) - << getAttrName(AI) << Param->getSourceRange(); + << AI << Param->getSourceRange(); return false; } return true; @@ -787,8 +893,7 @@ static void handleAllocSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { const auto *FD = cast<FunctionDecl>(D); if (!FD->getReturnType()->isPointerType()) { - S.Diag(AL.getLoc(), diag::warn_attribute_return_pointers_only) - << AL.getName(); + S.Diag(AL.getLoc(), diag::warn_attribute_return_pointers_only) << AL; return; } @@ -825,7 +930,7 @@ static bool checkTryLockFunAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL, if (!isIntOrBool(AL.getArgAsExpr(0))) { S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) - << AL.getName() << 1 << AANT_ArgumentIntOrBool; + << AL << 1 << AANT_ArgumentIntOrBool; return false; } @@ -907,8 +1012,7 @@ static bool checkFunctionConditionAttr(Sema &S, Decl *D, const ParsedAttr &AL, if (isa<FunctionDecl>(D) && !Cond->isValueDependent() && !Expr::isPotentialConstantExprUnevaluated(Cond, cast<FunctionDecl>(D), Diags)) { - S.Diag(AL.getLoc(), diag::err_attr_cond_never_constant_expr) - << AL.getName(); + S.Diag(AL.getLoc(), diag::err_attr_cond_never_constant_expr) << AL; for (const PartialDiagnosticAt &PDiag : Diags) S.Diag(PDiag.first, PDiag.second); return false; @@ -987,7 +1091,7 @@ static void handleDiagnoseIfAttr(Sema &S, Decl *D, const ParsedAttr &AL) { DiagnoseIfAttr::DiagnosticType DiagType; if (!DiagnoseIfAttr::ConvertStrToDiagnosticType(DiagTypeStr, DiagType)) { - S.Diag(AL.getArgAsExpr(2)->getLocStart(), + S.Diag(AL.getArgAsExpr(2)->getBeginLoc(), diag::err_diagnose_if_invalid_diagnostic_type); return; } @@ -1002,8 +1106,7 @@ static void handleDiagnoseIfAttr(Sema &S, Decl *D, const ParsedAttr &AL) { static void handlePassObjectSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (D->hasAttr<PassObjectSizeAttr>()) { - S.Diag(D->getLocStart(), diag::err_attribute_only_once_per_parameter) - << AL.getName(); + S.Diag(D->getBeginLoc(), diag::err_attribute_only_once_per_parameter) << AL; return; } @@ -1016,8 +1119,8 @@ static void handlePassObjectSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // __builtin_object_size. So, it has the same constraints as that second // argument; namely, it must be in the range [0, 3]. if (Type > 3) { - S.Diag(E->getLocStart(), diag::err_attribute_argument_outof_range) - << AL.getName() << 0 << 3 << E->getSourceRange(); + S.Diag(E->getBeginLoc(), diag::err_attribute_argument_outof_range) + << AL << 0 << 3 << E->getSourceRange(); return; } @@ -1026,8 +1129,7 @@ static void handlePassObjectSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // At this point, we have no clue if `D` belongs to a function declaration or // definition, so we defer the constness check until later. if (!cast<ParmVarDecl>(D)->getType()->isPointerType()) { - S.Diag(D->getLocStart(), diag::err_attribute_pointers_only) - << AL.getName() << 1; + S.Diag(D->getBeginLoc(), diag::err_attribute_pointers_only) << AL << 1; return; } @@ -1042,13 +1144,13 @@ static void handleConsumableAttr(Sema &S, Decl *D, const ParsedAttr &AL) { IdentifierLoc *IL = AL.getArgAsIdent(0); if (!ConsumableAttr::ConvertStrToConsumedState(IL->Ident->getName(), DefaultState)) { - S.Diag(IL->Loc, diag::warn_attribute_type_not_supported) - << AL.getName() << IL->Ident; + S.Diag(IL->Loc, diag::warn_attribute_type_not_supported) << AL + << IL->Ident; return; } } else { S.Diag(AL.getLoc(), diag::err_attribute_argument_type) - << AL.getName() << AANT_ArgumentIdentifier; + << AL << AANT_ArgumentIdentifier; return; } @@ -1059,8 +1161,7 @@ static void handleConsumableAttr(Sema &S, Decl *D, const ParsedAttr &AL) { static bool checkForConsumableClass(Sema &S, const CXXMethodDecl *MD, const ParsedAttr &AL) { - ASTContext &CurrContext = S.getASTContext(); - QualType ThisType = MD->getThisType(CurrContext)->getPointeeType(); + QualType ThisType = MD->getThisType()->getPointeeType(); if (const CXXRecordDecl *RD = ThisType->getAsCXXRecordDecl()) { if (!RD->hasAttr<ConsumableAttr>()) { @@ -1098,8 +1199,7 @@ static void handleCallableWhenAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!CallableWhenAttr::ConvertStrToConsumedState(StateString, CallableState)) { - S.Diag(Loc, diag::warn_attribute_type_not_supported) - << AL.getName() << StateString; + S.Diag(Loc, diag::warn_attribute_type_not_supported) << AL << StateString; return; } @@ -1121,12 +1221,12 @@ static void handleParamTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!ParamTypestateAttr::ConvertStrToConsumedState(StateString, ParamState)) { S.Diag(Ident->Loc, diag::warn_attribute_type_not_supported) - << AL.getName() << StateString; + << AL << StateString; return; } } else { - S.Diag(AL.getLoc(), diag::err_attribute_argument_type) << - AL.getName() << AANT_ArgumentIdentifier; + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL << AANT_ArgumentIdentifier; return; } @@ -1154,13 +1254,13 @@ static void handleReturnTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { IdentifierLoc *IL = AL.getArgAsIdent(0); if (!ReturnTypestateAttr::ConvertStrToConsumedState(IL->Ident->getName(), ReturnState)) { - S.Diag(IL->Loc, diag::warn_attribute_type_not_supported) - << AL.getName() << IL->Ident; + S.Diag(IL->Loc, diag::warn_attribute_type_not_supported) << AL + << IL->Ident; return; } } else { - S.Diag(AL.getLoc(), diag::err_attribute_argument_type) << - AL.getName() << AANT_ArgumentIdentifier; + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL << AANT_ArgumentIdentifier; return; } @@ -1174,7 +1274,7 @@ static void handleReturnTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // //} else if (const CXXConstructorDecl *Constructor = // dyn_cast<CXXConstructorDecl>(D)) { - // ReturnType = Constructor->getThisType(S.getASTContext())->getPointeeType(); + // ReturnType = Constructor->getThisType()->getPointeeType(); // //} else { // @@ -1203,13 +1303,13 @@ static void handleSetTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { IdentifierLoc *Ident = AL.getArgAsIdent(0); StringRef Param = Ident->Ident->getName(); if (!SetTypestateAttr::ConvertStrToConsumedState(Param, NewState)) { - S.Diag(Ident->Loc, diag::warn_attribute_type_not_supported) - << AL.getName() << Param; + S.Diag(Ident->Loc, diag::warn_attribute_type_not_supported) << AL + << Param; return; } } else { - S.Diag(AL.getLoc(), diag::err_attribute_argument_type) << - AL.getName() << AANT_ArgumentIdentifier; + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL << AANT_ArgumentIdentifier; return; } @@ -1227,13 +1327,13 @@ static void handleTestTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { IdentifierLoc *Ident = AL.getArgAsIdent(0); StringRef Param = Ident->Ident->getName(); if (!TestTypestateAttr::ConvertStrToConsumedState(Param, TestState)) { - S.Diag(Ident->Loc, diag::warn_attribute_type_not_supported) - << AL.getName() << Param; + S.Diag(Ident->Loc, diag::warn_attribute_type_not_supported) << AL + << Param; return; } } else { - S.Diag(AL.getLoc(), diag::err_attribute_argument_type) << - AL.getName() << AANT_ArgumentIdentifier; + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL << AANT_ArgumentIdentifier; return; } @@ -1261,7 +1361,7 @@ static void handlePackedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (BitfieldByteAligned) // The PS4 target needs to maintain ABI backwards compatibility. S.Diag(AL.getLoc(), diag::warn_attribute_ignored_for_field_of_type) - << AL.getName() << FD->getType(); + << AL << FD->getType(); else FD->addAttr(::new (S.Context) PackedAttr( AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); @@ -1275,7 +1375,7 @@ static void handlePackedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } } else - S.Diag(AL.getLoc(), diag::warn_attribute_ignored) << AL.getName(); + S.Diag(AL.getLoc(), diag::warn_attribute_ignored) << AL; } static bool checkIBOutletCommon(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -1285,19 +1385,19 @@ static bool checkIBOutletCommon(Sema &S, Decl *D, const ParsedAttr &AL) { if (const auto *VD = dyn_cast<ObjCIvarDecl>(D)) { if (!VD->getType()->getAs<ObjCObjectPointerType>()) { S.Diag(AL.getLoc(), diag::warn_iboutlet_object_type) - << AL.getName() << VD->getType() << 0; + << AL << VD->getType() << 0; return false; } } else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(D)) { if (!PD->getType()->getAs<ObjCObjectPointerType>()) { S.Diag(AL.getLoc(), diag::warn_iboutlet_object_type) - << AL.getName() << PD->getType() << 1; + << AL << PD->getType() << 1; return false; } } else { - S.Diag(AL.getLoc(), diag::warn_attribute_iboutlet) << AL.getName(); + S.Diag(AL.getLoc(), diag::warn_attribute_iboutlet) << AL; return false; } @@ -1317,8 +1417,7 @@ static void handleIBOutletCollection(Sema &S, Decl *D, const ParsedAttr &AL) { // The iboutletcollection attribute can have zero or one arguments. if (AL.getNumArgs() > 1) { - S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) - << AL.getName() << 1; + S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1; return; } @@ -1390,10 +1489,10 @@ static bool attrNonNullArgCheck(Sema &S, QualType T, const ParsedAttr &AL, if (!S.isValidPointerAttrType(T)) { if (isReturnValue) S.Diag(AL.getLoc(), diag::warn_attribute_return_pointers_only) - << AL.getName() << AttrParmRange << TypeRange; + << AL << AttrParmRange << TypeRange; else S.Diag(AL.getLoc(), diag::warn_attribute_pointers_only) - << AL.getName() << AttrParmRange << TypeRange << 0; + << AL << AttrParmRange << TypeRange << 0; return false; } return true; @@ -1486,7 +1585,7 @@ static void handleNoEscapeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { QualType T = cast<ParmVarDecl>(D)->getType(); if (!S.isValidPointerAttrType(T, /* RefOkay */ true)) { S.Diag(AL.getLoc(), diag::warn_attribute_pointers_only) - << AL.getName() << AL.getRange() << 0; + << AL << AL.getRange() << 0; return; } @@ -1579,7 +1678,7 @@ void Sema::AddAllocAlignAttr(SourceRange AttrRange, Decl *D, Expr *ParamExpr, QualType Ty = getFunctionOrMethodParamType(D, Idx.getASTIndex()); if (!Ty->isDependentType() && !Ty->isIntegralType(Context)) { - Diag(ParamExpr->getLocStart(), diag::err_attribute_integers_only) + Diag(ParamExpr->getBeginLoc(), diag::err_attribute_integers_only) << &TmpAttr << FuncDecl->getParamDecl(Idx.getASTIndex())->getSourceRange(); return; @@ -1611,7 +1710,7 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!AL.isArgIdent(0)) { S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) - << AL.getName() << 1 << AANT_ArgumentIdentifier; + << AL << 1 << AANT_ArgumentIdentifier; return; } @@ -1625,15 +1724,13 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) { case OwnershipAttr::Takes: case OwnershipAttr::Holds: if (AL.getNumArgs() < 2) { - S.Diag(AL.getLoc(), diag::err_attribute_too_few_arguments) - << AL.getName() << 2; + S.Diag(AL.getLoc(), diag::err_attribute_too_few_arguments) << AL << 2; return; } break; case OwnershipAttr::Returns: if (AL.getNumArgs() > 2) { - S.Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) - << AL.getName() << 1; + S.Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) << AL << 1; return; } break; @@ -1668,8 +1765,8 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) { break; } if (-1 != Err) { - S.Diag(AL.getLoc(), diag::err_ownership_type) << AL.getName() << Err - << Ex->getSourceRange(); + S.Diag(AL.getLoc(), diag::err_ownership_type) << AL << Err + << Ex->getSourceRange(); return; } @@ -1679,8 +1776,7 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // index. 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() << I; + S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << I; return; } else if (K == OwnershipAttr::Returns && I->getOwnKind() == OwnershipAttr::Returns) { @@ -1710,8 +1806,7 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) { static void handleWeakRefAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Check the attribute arguments. if (AL.getNumArgs() > 1) { - S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) - << AL.getName() << 1; + S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1; return; } @@ -1812,7 +1907,16 @@ static void handleAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } } - // FIXME: check if target symbol exists in current file + // Mark target used to prevent unneeded-internal-declaration warnings. + if (!S.LangOpts.CPlusPlus) { + // FIXME: demangle Str for C++, as the attribute refers to the mangled + // linkage name, not the pre-mangled identifier. + const DeclarationNameInfo target(&S.Context.Idents.get(Str), AL.getLoc()); + LookupResult LR(S, target, Sema::LookupOrdinaryName); + if (S.LookupQualifiedName(LR, S.getCurLexicalContext())) + for (NamedDecl *ND : LR) + ND->markUsed(S.Context); + } D->addAttr(::new (S.Context) AliasAttr(AL.getRange(), S.Context, Str, AL.getAttributeSpellingListIndex())); @@ -1846,11 +1950,19 @@ static void handleRestrictAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } S.Diag(AL.getLoc(), diag::warn_attribute_return_pointers_only) - << AL.getName() << getFunctionOrMethodResultSourceRange(D); + << AL << getFunctionOrMethodResultSourceRange(D); } static void handleCPUSpecificAttr(Sema &S, Decl *D, const ParsedAttr &AL) { FunctionDecl *FD = cast<FunctionDecl>(D); + + if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) { + if (MD->getParent()->isLambda()) { + S.Diag(AL.getLoc(), diag::err_attribute_dll_lambda) << AL; + return; + } + } + if (!checkAttributeAtLeastNumArgs(S, AL, 1)) return; @@ -1858,7 +1970,7 @@ static void handleCPUSpecificAttr(Sema &S, Decl *D, const ParsedAttr &AL) { for (unsigned ArgNo = 0; ArgNo < getNumAttributeArgs(AL); ++ArgNo) { if (!AL.isArgIdent(ArgNo)) { S.Diag(AL.getLoc(), diag::err_attribute_argument_type) - << AL.getName() << AANT_ArgumentIdentifier; + << AL << AANT_ArgumentIdentifier; return; } @@ -1896,18 +2008,16 @@ static void handleCPUSpecificAttr(Sema &S, Decl *D, const ParsedAttr &AL) { static void handleCommonAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (S.LangOpts.CPlusPlus) { S.Diag(AL.getLoc(), diag::err_attribute_not_supported_in_lang) - << AL.getName() << AttributeLangSupport::Cpp; + << AL << AttributeLangSupport::Cpp; return; } - if (CommonAttr *CA = S.mergeCommonAttr(D, AL.getRange(), AL.getName(), - AL.getAttributeSpellingListIndex())) + if (CommonAttr *CA = S.mergeCommonAttr(D, AL)) D->addAttr(CA); } static void handleNakedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (checkAttrMutualExclusion<DisableTailCallsAttr>(S, D, AL.getRange(), - AL.getName())) + if (checkAttrMutualExclusion<DisableTailCallsAttr>(S, D, AL)) return; if (AL.isDeclspecAttribute()) { @@ -1916,7 +2026,7 @@ static void handleNakedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (Arch != llvm::Triple::x86 && (Arch != llvm::Triple::arm && Arch != llvm::Triple::thumb)) { S.Diag(AL.getLoc(), diag::err_attribute_not_supported_on_arch) - << AL.getName() << Triple.getArchName(); + << AL << Triple.getArchName(); return; } } @@ -1930,7 +2040,7 @@ static void handleNoReturnAttr(Sema &S, Decl *D, const ParsedAttr &Attrs) { if (!isa<ObjCMethodDecl>(D)) { S.Diag(Attrs.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attrs.getName() << ExpectedFunctionOrMethod; + << Attrs << ExpectedFunctionOrMethod; return; } @@ -1957,7 +2067,7 @@ bool Sema::CheckAttrNoArgs(const ParsedAttr &Attrs) { bool Sema::CheckAttrTarget(const ParsedAttr &AL) { // Check whether the attribute is valid on the current target. if (!AL.existsInTarget(Context.getTargetInfo())) { - Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) << AL.getName(); + Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) << AL; AL.setInvalid(); return true; } @@ -1973,10 +2083,10 @@ static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D, const ParsedAttr &AL) { ValueDecl *VD = dyn_cast<ValueDecl>(D); if (!VD || (!VD->getType()->isBlockPointerType() && !VD->getType()->isFunctionPointerType())) { - S.Diag(AL.getLoc(), - AL.isCXX11Attribute() ? diag::err_attribute_wrong_decl_type - : diag::warn_attribute_wrong_decl_type) - << AL.getName() << ExpectedFunctionMethodOrBlock; + S.Diag(AL.getLoc(), AL.isCXX11Attribute() + ? diag::err_attribute_wrong_decl_type + : diag::warn_attribute_wrong_decl_type) + << AL << ExpectedFunctionMethodOrBlock; return; } } @@ -2065,7 +2175,7 @@ static void handleUnusedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // If this is spelled as the standard C++17 attribute, but not in C++17, warn // about using it as an extension. if (!S.getLangOpts().CPlusPlus17 && IsCXX17Attr) - S.Diag(AL.getLoc(), diag::ext_cxx17_attr) << AL.getName(); + S.Diag(AL.getLoc(), diag::ext_cxx17_attr) << AL; D->addAttr(::new (S.Context) UnusedAttr( AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); @@ -2108,7 +2218,7 @@ static void handleObjCSuppresProtocolAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!cast<ObjCProtocolDecl>(D)->isThisDeclarationADefinition()) { S.Diag(AL.getLoc(), diag::err_objc_attr_protocol_requires_definition) - << AL.getName() << AL.getRange(); + << AL << AL.getRange(); return; } @@ -2365,6 +2475,15 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (const auto *SE = dyn_cast_or_null<StringLiteral>(AL.getReplacementExpr())) Replacement = SE->getString(); + if (II->isStr("swift")) { + if (Introduced.isValid() || Obsoleted.isValid() || + (!IsUnavailable && !Deprecated.isValid())) { + S.Diag(AL.getLoc(), + diag::warn_availability_swift_unavailable_deprecated_only); + return; + } + } + AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, AL.getRange(), II, false/*Implicit*/, Introduced.Version, @@ -2506,8 +2625,7 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const ParsedAttr &AL, bool isTypeVisibility) { // Visibility attributes don't mean anything on a typedef. if (isa<TypedefNameDecl>(D)) { - S.Diag(AL.getRange().getBegin(), diag::warn_attribute_ignored) - << AL.getName(); + S.Diag(AL.getRange().getBegin(), diag::warn_attribute_ignored) << AL; return; } @@ -2517,7 +2635,7 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const ParsedAttr &AL, isa<ObjCInterfaceDecl>(D) || isa<NamespaceDecl>(D))) { S.Diag(AL.getRange().getBegin(), diag::err_attribute_wrong_decl_type) - << AL.getName() << ExpectedTypeOrNamespace; + << AL << ExpectedTypeOrNamespace; return; } @@ -2529,8 +2647,8 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const ParsedAttr &AL, VisibilityAttr::VisibilityType type; if (!VisibilityAttr::ConvertStrToVisibilityType(TypeStr, type)) { - S.Diag(LiteralLoc, diag::warn_attribute_type_not_supported) - << AL.getName() << TypeStr; + S.Diag(LiteralLoc, diag::warn_attribute_type_not_supported) << AL + << TypeStr; return; } @@ -2559,15 +2677,14 @@ static void handleObjCMethodFamilyAttr(Sema &S, Decl *D, const ParsedAttr &AL) { const auto *M = cast<ObjCMethodDecl>(D); if (!AL.isArgIdent(0)) { S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) - << AL.getName() << 1 << AANT_ArgumentIdentifier; + << AL << 1 << AANT_ArgumentIdentifier; return; } IdentifierLoc *IL = AL.getArgAsIdent(0); ObjCMethodFamilyAttr::FamilyKind F; if (!ObjCMethodFamilyAttr::ConvertStrToFamilyKind(IL->Ident->getName(), F)) { - S.Diag(IL->Loc, diag::warn_attribute_type_not_supported) - << AL.getName() << IL->Ident; + S.Diag(IL->Loc, diag::warn_attribute_type_not_supported) << AL << IL->Ident; return; } @@ -2631,15 +2748,14 @@ static void handleObjCIndependentClass(Sema &S, Decl *D, const ParsedAttr &AL) { static void handleBlocksAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!AL.isArgIdent(0)) { S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) - << AL.getName() << 1 << AANT_ArgumentIdentifier; + << AL << 1 << AANT_ArgumentIdentifier; return; } IdentifierInfo *II = AL.getArgAsIdent(0)->Ident; BlocksAttr::BlockType type; if (!BlocksAttr::ConvertStrToBlockType(II->getName(), type)) { - S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) - << AL.getName() << II; + S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << II; return; } @@ -2656,8 +2772,7 @@ static void handleSentinelAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (E->isTypeDependent() || E->isValueDependent() || !E->isIntegerConstantExpr(Idx, S.Context)) { S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) - << AL.getName() << 1 << AANT_ArgumentIntegerConstant - << E->getSourceRange(); + << AL << 1 << AANT_ArgumentIntegerConstant << E->getSourceRange(); return; } @@ -2677,8 +2792,7 @@ static void handleSentinelAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (E->isTypeDependent() || E->isValueDependent() || !E->isIntegerConstantExpr(Idx, S.Context)) { S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) - << AL.getName() << 2 << AANT_ArgumentIntegerConstant - << E->getSourceRange(); + << AL << 2 << AANT_ArgumentIntegerConstant << E->getSourceRange(); return; } nullPos = Idx.getZExtValue(); @@ -2726,12 +2840,12 @@ static void handleSentinelAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } } else { S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) - << AL.getName() << ExpectedFunctionMethodOrBlock; + << AL << ExpectedFunctionMethodOrBlock; return; } } else { S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) - << AL.getName() << ExpectedFunctionMethodOrBlock; + << AL << ExpectedFunctionMethodOrBlock; return; } D->addAttr(::new (S.Context) @@ -2742,14 +2856,12 @@ static void handleSentinelAttr(Sema &S, Decl *D, const ParsedAttr &AL) { static void handleWarnUnusedResult(Sema &S, Decl *D, const ParsedAttr &AL) { if (D->getFunctionType() && D->getFunctionType()->getReturnType()->isVoidType()) { - S.Diag(AL.getLoc(), diag::warn_attribute_void_function_method) - << AL.getName() << 0; + S.Diag(AL.getLoc(), diag::warn_attribute_void_function_method) << AL << 0; return; } if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) if (MD->getReturnType()->isVoidType()) { - S.Diag(AL.getLoc(), diag::warn_attribute_void_function_method) - << AL.getName() << 1; + S.Diag(AL.getLoc(), diag::warn_attribute_void_function_method) << AL << 1; return; } @@ -2757,7 +2869,7 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const ParsedAttr &AL) { // about using it as an extension. if (!S.getLangOpts().CPlusPlus17 && AL.isCXX11Attribute() && !AL.getScopeName()) - S.Diag(AL.getLoc(), diag::ext_cxx17_attr) << AL.getName(); + S.Diag(AL.getLoc(), diag::ext_cxx17_attr) << AL; D->addAttr(::new (S.Context) WarnUnusedResultAttr(AL.getRange(), S.Context, @@ -2777,7 +2889,7 @@ static void handleWeakImportAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Nothing to warn about here. } else S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) - << AL.getName() << ExpectedVariableOrFunction; + << AL << ExpectedVariableOrFunction; return; } @@ -2793,11 +2905,12 @@ static void handleWorkGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) { uint32_t WGSize[3]; for (unsigned i = 0; i < 3; ++i) { const Expr *E = AL.getArgAsExpr(i); - if (!checkUInt32Argument(S, AL, E, WGSize[i], i)) + if (!checkUInt32Argument(S, AL, E, WGSize[i], i, + /*StrictlyUnsigned=*/true)) return; if (WGSize[i] == 0) { S.Diag(AL.getLoc(), diag::err_attribute_argument_is_zero) - << AL.getName() << E->getSourceRange(); + << AL << E->getSourceRange(); return; } } @@ -2806,7 +2919,7 @@ static void handleWorkGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) { if (Existing && !(Existing->getXDim() == WGSize[0] && Existing->getYDim() == WGSize[1] && Existing->getZDim() == WGSize[2])) - S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL.getName(); + S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL; D->addAttr(::new (S.Context) WorkGroupAttr(AL.getRange(), S.Context, WGSize[0], WGSize[1], WGSize[2], @@ -2821,14 +2934,14 @@ static void handleSubGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) { return; if (SGSize == 0) { S.Diag(AL.getLoc(), diag::err_attribute_argument_is_zero) - << AL.getName() << E->getSourceRange(); + << AL << E->getSourceRange(); return; } OpenCLIntelReqdSubGroupSizeAttr *Existing = D->getAttr<OpenCLIntelReqdSubGroupSizeAttr>(); if (Existing && Existing->getSubGroupSize() != SGSize) - S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL.getName(); + S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL; D->addAttr(::new (S.Context) OpenCLIntelReqdSubGroupSizeAttr( AL.getRange(), S.Context, SGSize, @@ -2837,8 +2950,7 @@ static void handleSubGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) { static void handleVecTypeHint(Sema &S, Decl *D, const ParsedAttr &AL) { if (!AL.hasParsedType()) { - S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) - << AL.getName() << 1; + S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1; return; } @@ -2856,7 +2968,7 @@ static void handleVecTypeHint(Sema &S, Decl *D, const ParsedAttr &AL) { if (VecTypeHintAttr *A = D->getAttr<VecTypeHintAttr>()) { if (!S.Context.hasSameType(A->getTypeHint(), ParmType)) { - S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL.getName(); + S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL; return; } } @@ -3030,7 +3142,7 @@ static void handleMinVectorWidthAttr(Sema &S, Decl *D, const ParsedAttr &AL) { MinVectorWidthAttr *Existing = D->getAttr<MinVectorWidthAttr>(); if (Existing && Existing->getVectorWidth() != VecWidth) { - S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL.getName(); + S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL; return; } @@ -3100,7 +3212,7 @@ static void handleEnumExtensibilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!AL.isArgIdent(0)) { S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) - << AL.getName() << 0 << AANT_ArgumentIdentifier; + << AL << 0 << AANT_ArgumentIdentifier; return; } @@ -3108,8 +3220,7 @@ static void handleEnumExtensibilityAttr(Sema &S, Decl *D, IdentifierInfo *II = AL.getArgAsIdent(0)->Ident; if (!EnumExtensibilityAttr::ConvertStrToKind(II->getName(), ExtensibilityKind)) { - S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) - << AL.getName() << II; + S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << II; return; } @@ -3188,7 +3299,7 @@ static FormatAttrKind getFormatAttrKind(StringRef Format) { /// http://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Attributes.html static void handleInitPriorityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!S.getLangOpts().CPlusPlus) { - S.Diag(AL.getLoc(), diag::warn_attribute_ignored) << AL.getName(); + S.Diag(AL.getLoc(), diag::warn_attribute_ignored) << AL; return; } @@ -3215,7 +3326,7 @@ static void handleInitPriorityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (prioritynum < 101 || prioritynum > 65535) { S.Diag(AL.getLoc(), diag::err_attribute_argument_outof_range) - << E->getSourceRange() << AL.getName() << 101 << 65535; + << E->getSourceRange() << AL << 101 << 65535; AL.setInvalid(); return; } @@ -3250,7 +3361,7 @@ FormatAttr *Sema::mergeFormatAttr(Decl *D, SourceRange Range, static void handleFormatAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!AL.isArgIdent(0)) { S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) - << AL.getName() << 1 << AANT_ArgumentIdentifier; + << AL << 1 << AANT_ArgumentIdentifier; return; } @@ -3275,7 +3386,7 @@ static void handleFormatAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (Kind == InvalidFormat) { S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) - << AL.getName() << II->getName(); + << AL << II->getName(); return; } @@ -3287,7 +3398,7 @@ static void handleFormatAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (Idx < 1 || Idx > NumArgs) { S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) - << AL.getName() << 2 << IdxExpr->getSourceRange(); + << AL << 2 << IdxExpr->getSourceRange(); return; } @@ -3358,7 +3469,7 @@ static void handleFormatAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // if 0 it disables parameter checking (to use with e.g. va_list) } else if (FirstArg != 0 && FirstArg != NumArgs) { S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) - << AL.getName() << 3 << FirstArgExpr->getSourceRange(); + << AL << 3 << FirstArgExpr->getSourceRange(); return; } @@ -3379,8 +3490,8 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { RD = dyn_cast<RecordDecl>(D); if (!RD || !RD->isUnion()) { - S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) - << AL.getName() << ExpectedUnion; + S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) << AL + << ExpectedUnion; return; } @@ -3513,8 +3624,7 @@ void Sema::AddAlignValueAttr(SourceRange AttrRange, Decl *D, Expr *E, static void handleAlignedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // check the attribute arguments. if (AL.getNumArgs() > 1) { - S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) - << AL.getName() << 1; + S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1; return; } @@ -3794,8 +3904,8 @@ static void handleModeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // This attribute isn't documented, but glibc uses it. It changes // the width of an int or unsigned int to the specified size. if (!AL.isArgIdent(0)) { - S.Diag(AL.getLoc(), diag::err_attribute_argument_type) << AL.getName() - << AANT_ArgumentIdentifier; + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL << AANT_ArgumentIdentifier; return; } @@ -3968,26 +4078,55 @@ AlwaysInlineAttr *Sema::mergeAlwaysInlineAttr(Decl *D, SourceRange Range, AttrSpellingListIndex); } -CommonAttr *Sema::mergeCommonAttr(Decl *D, SourceRange Range, - IdentifierInfo *Ident, - unsigned AttrSpellingListIndex) { - if (checkAttrMutualExclusion<InternalLinkageAttr>(*this, D, Range, Ident)) +CommonAttr *Sema::mergeCommonAttr(Decl *D, const ParsedAttr &AL) { + if (checkAttrMutualExclusion<InternalLinkageAttr>(*this, D, AL)) + return nullptr; + + return ::new (Context) + CommonAttr(AL.getRange(), Context, AL.getAttributeSpellingListIndex()); +} + +CommonAttr *Sema::mergeCommonAttr(Decl *D, const CommonAttr &AL) { + if (checkAttrMutualExclusion<InternalLinkageAttr>(*this, D, AL)) return nullptr; - return ::new (Context) CommonAttr(Range, Context, AttrSpellingListIndex); + return ::new (Context) + CommonAttr(AL.getRange(), Context, AL.getSpellingListIndex()); } +InternalLinkageAttr *Sema::mergeInternalLinkageAttr(Decl *D, + const ParsedAttr &AL) { + if (const auto *VD = dyn_cast<VarDecl>(D)) { + // Attribute applies to Var but not any subclass of it (like ParmVar, + // ImplicitParm or VarTemplateSpecialization). + if (VD->getKind() != Decl::Var) { + Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) + << AL << (getLangOpts().CPlusPlus ? ExpectedFunctionVariableOrClass + : ExpectedVariableOrFunction); + return nullptr; + } + // Attribute does not apply to non-static local variables. + if (VD->hasLocalStorage()) { + Diag(VD->getLocation(), diag::warn_internal_linkage_local_storage); + return nullptr; + } + } + + if (checkAttrMutualExclusion<CommonAttr>(*this, D, AL)) + return nullptr; + + return ::new (Context) InternalLinkageAttr( + AL.getRange(), Context, AL.getAttributeSpellingListIndex()); +} InternalLinkageAttr * -Sema::mergeInternalLinkageAttr(Decl *D, SourceRange Range, - IdentifierInfo *Ident, - unsigned AttrSpellingListIndex) { +Sema::mergeInternalLinkageAttr(Decl *D, const InternalLinkageAttr &AL) { if (const auto *VD = dyn_cast<VarDecl>(D)) { // Attribute applies to Var but not any subclass of it (like ParmVar, // ImplicitParm or VarTemplateSpecialization). if (VD->getKind() != Decl::Var) { - Diag(Range.getBegin(), diag::warn_attribute_wrong_decl_type) - << Ident << (getLangOpts().CPlusPlus ? ExpectedFunctionVariableOrClass - : ExpectedVariableOrFunction); + Diag(AL.getLocation(), diag::warn_attribute_wrong_decl_type) + << &AL << (getLangOpts().CPlusPlus ? ExpectedFunctionVariableOrClass + : ExpectedVariableOrFunction); return nullptr; } // Attribute does not apply to non-static local variables. @@ -3997,11 +4136,11 @@ Sema::mergeInternalLinkageAttr(Decl *D, SourceRange Range, } } - if (checkAttrMutualExclusion<CommonAttr>(*this, D, Range, Ident)) + if (checkAttrMutualExclusion<CommonAttr>(*this, D, AL)) return nullptr; return ::new (Context) - InternalLinkageAttr(Range, Context, AttrSpellingListIndex); + InternalLinkageAttr(AL.getRange(), Context, AL.getSpellingListIndex()); } MinSizeAttr *Sema::mergeMinSizeAttr(Decl *D, SourceRange Range, @@ -4039,8 +4178,7 @@ OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D, SourceRange Range, } static void handleAlwaysInlineAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (checkAttrMutualExclusion<NotTailCalledAttr>(S, D, AL.getRange(), - AL.getName())) + if (checkAttrMutualExclusion<NotTailCalledAttr>(S, D, AL)) return; if (AlwaysInlineAttr *Inline = S.mergeAlwaysInlineAttr( @@ -4062,8 +4200,7 @@ static void handleOptimizeNoneAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } static void handleConstantAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (checkAttrMutualExclusion<CUDASharedAttr>(S, D, AL.getRange(), - AL.getName())) + if (checkAttrMutualExclusion<CUDASharedAttr>(S, D, AL)) return; const auto *VD = cast<VarDecl>(D); if (!VD->hasGlobalStorage()) { @@ -4075,13 +4212,12 @@ static void handleConstantAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } static void handleSharedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (checkAttrMutualExclusion<CUDAConstantAttr>(S, D, AL.getRange(), - AL.getName())) + if (checkAttrMutualExclusion<CUDAConstantAttr>(S, D, AL)) return; const auto *VD = cast<VarDecl>(D); // extern __shared__ is only allowed on arrays with no length (e.g. // "int x[]"). - if (!S.getLangOpts().CUDARelocatableDeviceCode && VD->hasExternalStorage() && + if (!S.getLangOpts().GPURelocatableDeviceCode && VD->hasExternalStorage() && !isa<IncompleteArrayType>(VD->getType())) { S.Diag(AL.getLoc(), diag::err_cuda_extern_shared) << VD; return; @@ -4095,10 +4231,8 @@ static void handleSharedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } static void handleGlobalAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (checkAttrMutualExclusion<CUDADeviceAttr>(S, D, AL.getRange(), - AL.getName()) || - checkAttrMutualExclusion<CUDAHostAttr>(S, D, AL.getRange(), - AL.getName())) { + if (checkAttrMutualExclusion<CUDADeviceAttr>(S, D, AL) || + checkAttrMutualExclusion<CUDAHostAttr>(S, D, AL)) { return; } const auto *FD = cast<FunctionDecl>(D); @@ -4112,15 +4246,15 @@ static void handleGlobalAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } if (const auto *Method = dyn_cast<CXXMethodDecl>(FD)) { if (Method->isInstance()) { - S.Diag(Method->getLocStart(), diag::err_kern_is_nonstatic_method) + S.Diag(Method->getBeginLoc(), diag::err_kern_is_nonstatic_method) << Method; return; } - S.Diag(Method->getLocStart(), diag::warn_kern_is_method) << Method; + S.Diag(Method->getBeginLoc(), diag::warn_kern_is_method) << Method; } // Only warn for "inline" when compiling for host, to cut down on noise. if (FD->isInlineSpecified() && !S.getLangOpts().CUDAIsDevice) - S.Diag(FD->getLocStart(), diag::warn_kern_is_inline) << FD; + S.Diag(FD->getBeginLoc(), diag::warn_kern_is_inline) << FD; D->addAttr(::new (S.Context) CUDAGlobalAttr(AL.getRange(), S.Context, @@ -4150,7 +4284,7 @@ static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!isa<ObjCMethodDecl>(D)) { S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) - << AL.getName() << ExpectedFunctionOrMethod; + << AL << ExpectedFunctionOrMethod; return; } @@ -4222,6 +4356,11 @@ static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) { AL.getAttributeSpellingListIndex())); return; } + case ParsedAttr::AT_AArch64VectorPcs: + D->addAttr(::new(S.Context) + AArch64VectorPcsAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); + return; case ParsedAttr::AT_IntelOclBicc: D->addAttr(::new (S.Context) IntelOclBiccAttr(AL.getRange(), S.Context, @@ -4299,6 +4438,9 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC, case ParsedAttr::AT_VectorCall: CC = CC_X86VectorCall; break; + case ParsedAttr::AT_AArch64VectorPcs: + CC = CC_AArch64VectorCall; + break; case ParsedAttr::AT_RegCall: CC = CC_X86RegCall; break; @@ -4344,7 +4486,7 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC, TargetInfo::CallingConvCheckResult A = TI.checkCallingConvention(CC); if (A != TargetInfo::CCCR_OK) { if (A == TargetInfo::CCCR_Warning) - Diag(Attrs.getLoc(), diag::warn_cconv_ignored) << Attrs.getName(); + Diag(Attrs.getLoc(), diag::warn_cconv_ignored) << Attrs; // This convention is not valid for the target. Use the default function or // method calling convention. @@ -4559,7 +4701,7 @@ static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!AL.isArgIdent(0)) { S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) - << AL.getName() << /* arg num = */ 1 << AANT_ArgumentIdentifier; + << AL << /* arg num = */ 1 << AANT_ArgumentIdentifier; return; } @@ -4579,8 +4721,7 @@ static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D, unsigned ArgumentIdxAST = ArgumentIdx.getASTIndex(); if (ArgumentIdxAST >= getFunctionOrMethodNumParams(D) || !getFunctionOrMethodParamType(D, ArgumentIdxAST)->isPointerType()) - S.Diag(AL.getLoc(), diag::err_attribute_pointers_only) - << AL.getName() << 0; + S.Diag(AL.getLoc(), diag::err_attribute_pointers_only) << AL << 0; } D->addAttr(::new (S.Context) ArgumentWithTypeTagAttr( @@ -4592,7 +4733,7 @@ static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!AL.isArgIdent(0)) { S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) - << AL.getName() << 1 << AANT_ArgumentIdentifier; + << AL << 1 << AANT_ArgumentIdentifier; return; } @@ -4601,7 +4742,7 @@ static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D, if (!isa<VarDecl>(D)) { S.Diag(AL.getLoc(), diag::err_attribute_wrong_decl_type) - << AL.getName() << ExpectedVariable; + << AL << ExpectedVariable; return; } @@ -4635,58 +4776,84 @@ static void handleXRayLogArgsAttr(Sema &S, Decl *D, const ParsedAttr &AL) { //===----------------------------------------------------------------------===// // Checker-specific attribute handlers. //===----------------------------------------------------------------------===// - static bool isValidSubjectOfNSReturnsRetainedAttribute(QualType QT) { return QT->isDependentType() || QT->isObjCRetainableType(); } -static bool isValidSubjectOfNSAttribute(Sema &S, QualType QT) { +static bool isValidSubjectOfNSAttribute(QualType QT) { return QT->isDependentType() || QT->isObjCObjectPointerType() || - S.Context.isObjCNSObjectType(QT); + QT->isObjCNSObjectType(); } -static bool isValidSubjectOfCFAttribute(Sema &S, QualType QT) { +static bool isValidSubjectOfCFAttribute(QualType QT) { return QT->isDependentType() || QT->isPointerType() || - isValidSubjectOfNSAttribute(S, QT); + isValidSubjectOfNSAttribute(QT); } -static void handleNSConsumedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - S.AddNSConsumedAttr(AL.getRange(), D, AL.getAttributeSpellingListIndex(), - AL.getKind() == ParsedAttr::AT_NSConsumed, - /*template instantiation*/ false); +static bool isValidSubjectOfOSAttribute(QualType QT) { + if (QT->isDependentType()) + return true; + QualType PT = QT->getPointeeType(); + return !PT.isNull() && PT->getAsCXXRecordDecl() != nullptr; } -void Sema::AddNSConsumedAttr(SourceRange AttrRange, Decl *D, - unsigned SpellingIndex, bool IsNSConsumed, - bool IsTemplateInstantiation) { - const auto *Param = cast<ParmVarDecl>(D); - bool TypeOK; - - if (IsNSConsumed) - TypeOK = isValidSubjectOfNSAttribute(*this, Param->getType()); - else - TypeOK = isValidSubjectOfCFAttribute(*this, Param->getType()); +void Sema::AddXConsumedAttr(Decl *D, SourceRange SR, unsigned SpellingIndex, + RetainOwnershipKind K, + bool IsTemplateInstantiation) { + ValueDecl *VD = cast<ValueDecl>(D); + switch (K) { + case RetainOwnershipKind::OS: + handleSimpleAttributeOrDiagnose<OSConsumedAttr>( + *this, VD, SR, SpellingIndex, isValidSubjectOfOSAttribute(VD->getType()), + diag::warn_ns_attribute_wrong_parameter_type, + /*ExtraArgs=*/SR, "os_consumed", /*pointers*/ 1); + return; + case RetainOwnershipKind::NS: + handleSimpleAttributeOrDiagnose<NSConsumedAttr>( + *this, VD, SR, SpellingIndex, isValidSubjectOfNSAttribute(VD->getType()), - if (!TypeOK) { - // These attributes are normally just advisory, but in ARC, ns_consumed - // is significant. Allow non-dependent code to contain inappropriate - // attributes even in ARC, but require template instantiations to be - // set up correctly. - Diag(D->getLocStart(), (IsTemplateInstantiation && IsNSConsumed && - getLangOpts().ObjCAutoRefCount - ? diag::err_ns_attribute_wrong_parameter_type - : diag::warn_ns_attribute_wrong_parameter_type)) - << AttrRange << (IsNSConsumed ? "ns_consumed" : "cf_consumed") - << (IsNSConsumed ? /*objc pointers*/ 0 : /*cf pointers*/ 1); + // These attributes are normally just advisory, but in ARC, ns_consumed + // is significant. Allow non-dependent code to contain inappropriate + // attributes even in ARC, but require template instantiations to be + // set up correctly. + ((IsTemplateInstantiation && getLangOpts().ObjCAutoRefCount) + ? diag::err_ns_attribute_wrong_parameter_type + : diag::warn_ns_attribute_wrong_parameter_type), + /*ExtraArgs=*/SR, "ns_consumed", /*objc pointers*/ 0); + return; + case RetainOwnershipKind::CF: + handleSimpleAttributeOrDiagnose<CFConsumedAttr>( + *this, VD, SR, SpellingIndex, + isValidSubjectOfCFAttribute(VD->getType()), + diag::warn_ns_attribute_wrong_parameter_type, + /*ExtraArgs=*/SR, "cf_consumed", /*pointers*/1); return; } +} - if (IsNSConsumed) - D->addAttr(::new (Context) - NSConsumedAttr(AttrRange, Context, SpellingIndex)); - else - D->addAttr(::new (Context) - CFConsumedAttr(AttrRange, Context, SpellingIndex)); +static Sema::RetainOwnershipKind +parsedAttrToRetainOwnershipKind(const ParsedAttr &AL) { + switch (AL.getKind()) { + case ParsedAttr::AT_CFConsumed: + case ParsedAttr::AT_CFReturnsRetained: + case ParsedAttr::AT_CFReturnsNotRetained: + return Sema::RetainOwnershipKind::CF; + case ParsedAttr::AT_OSConsumesThis: + case ParsedAttr::AT_OSConsumed: + case ParsedAttr::AT_OSReturnsRetained: + case ParsedAttr::AT_OSReturnsNotRetained: + case ParsedAttr::AT_OSReturnsRetainedOnZero: + case ParsedAttr::AT_OSReturnsRetainedOnNonZero: + return Sema::RetainOwnershipKind::OS; + case ParsedAttr::AT_NSConsumesSelf: + case ParsedAttr::AT_NSConsumed: + case ParsedAttr::AT_NSReturnsRetained: + case ParsedAttr::AT_NSReturnsNotRetained: + case ParsedAttr::AT_NSReturnsAutoreleased: + return Sema::RetainOwnershipKind::NS; + default: + llvm_unreachable("Wrong argument supplied"); + } } bool Sema::checkNSReturnsRetainedReturnType(SourceLocation Loc, QualType QT) { @@ -4698,25 +4865,40 @@ bool Sema::checkNSReturnsRetainedReturnType(SourceLocation Loc, QualType QT) { return true; } -static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, +/// \return whether the parameter is a pointer to OSObject pointer. +static bool isValidOSObjectOutParameter(const Decl *D) { + const auto *PVD = dyn_cast<ParmVarDecl>(D); + if (!PVD) + return false; + QualType QT = PVD->getType(); + QualType PT = QT->getPointeeType(); + return !PT.isNull() && isValidSubjectOfOSAttribute(PT); +} + +static void handleXReturnsXRetainedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { QualType ReturnType; + Sema::RetainOwnershipKind K = parsedAttrToRetainOwnershipKind(AL); - if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) + if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { ReturnType = MD->getReturnType(); - else if (S.getLangOpts().ObjCAutoRefCount && hasDeclarator(D) && - (AL.getKind() == ParsedAttr::AT_NSReturnsRetained)) + } else if (S.getLangOpts().ObjCAutoRefCount && hasDeclarator(D) && + (AL.getKind() == ParsedAttr::AT_NSReturnsRetained)) { return; // ignore: was handled as a type attribute - else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(D)) + } else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(D)) { ReturnType = PD->getType(); - else if (const auto *FD = dyn_cast<FunctionDecl>(D)) + } else if (const auto *FD = dyn_cast<FunctionDecl>(D)) { ReturnType = FD->getReturnType(); - else if (const auto *Param = dyn_cast<ParmVarDecl>(D)) { + } else if (const auto *Param = dyn_cast<ParmVarDecl>(D)) { + // Attributes on parameters are used for out-parameters, + // passed as pointers-to-pointers. + unsigned DiagID = K == Sema::RetainOwnershipKind::CF + ? /*pointer-to-CF-pointer*/2 + : /*pointer-to-OSObject-pointer*/3; ReturnType = Param->getType()->getPointeeType(); if (ReturnType.isNull()) { - S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_parameter_type) - << AL.getName() << /*pointer-to-CF*/2 - << AL.getRange(); + S.Diag(D->getBeginLoc(), diag::warn_ns_attribute_wrong_parameter_type) + << AL << DiagID << AL.getRange(); return; } } else if (AL.isUsedAsTypeAttr()) { @@ -4731,18 +4913,21 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, ExpectedDeclKind = ExpectedFunctionOrMethod; break; + case ParsedAttr::AT_OSReturnsRetained: + case ParsedAttr::AT_OSReturnsNotRetained: case ParsedAttr::AT_CFReturnsRetained: case ParsedAttr::AT_CFReturnsNotRetained: ExpectedDeclKind = ExpectedFunctionMethodOrParameter; break; } - S.Diag(D->getLocStart(), diag::warn_attribute_wrong_decl_type) - << AL.getRange() << AL.getName() << ExpectedDeclKind; + S.Diag(D->getBeginLoc(), diag::warn_attribute_wrong_decl_type) + << AL.getRange() << AL << ExpectedDeclKind; return; } bool TypeOK; bool Cf; + unsigned ParmDiagID = 2; // Pointer-to-CF-pointer switch (AL.getKind()) { default: llvm_unreachable("invalid ownership attribute"); case ParsedAttr::AT_NSReturnsRetained: @@ -4752,14 +4937,21 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, case ParsedAttr::AT_NSReturnsAutoreleased: case ParsedAttr::AT_NSReturnsNotRetained: - TypeOK = isValidSubjectOfNSAttribute(S, ReturnType); + TypeOK = isValidSubjectOfNSAttribute(ReturnType); Cf = false; break; case ParsedAttr::AT_CFReturnsRetained: case ParsedAttr::AT_CFReturnsNotRetained: - TypeOK = isValidSubjectOfCFAttribute(S, ReturnType); + TypeOK = isValidSubjectOfCFAttribute(ReturnType); + Cf = true; + break; + + case ParsedAttr::AT_OSReturnsRetained: + case ParsedAttr::AT_OSReturnsNotRetained: + TypeOK = isValidSubjectOfOSAttribute(ReturnType); Cf = true; + ParmDiagID = 3; // Pointer-to-OSObject-pointer break; } @@ -4768,9 +4960,8 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, return; if (isa<ParmVarDecl>(D)) { - S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_parameter_type) - << AL.getName() << /*pointer-to-CF*/2 - << AL.getRange(); + S.Diag(D->getBeginLoc(), diag::warn_ns_attribute_wrong_parameter_type) + << AL << ParmDiagID << AL.getRange(); } else { // Needs to be kept in sync with warn_ns_attribute_wrong_return_type. enum : unsigned { @@ -4782,9 +4973,8 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, SubjectKind = Method; else if (isa<ObjCPropertyDecl>(D)) SubjectKind = Property; - S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_return_type) - << AL.getName() << SubjectKind << Cf - << AL.getRange(); + S.Diag(D->getBeginLoc(), diag::warn_ns_attribute_wrong_return_type) + << AL << SubjectKind << Cf << AL.getRange(); } return; } @@ -4793,24 +4983,25 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, default: llvm_unreachable("invalid ownership attribute"); case ParsedAttr::AT_NSReturnsAutoreleased: - D->addAttr(::new (S.Context) NSReturnsAutoreleasedAttr( - AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); + handleSimpleAttribute<NSReturnsAutoreleasedAttr>(S, D, AL); return; case ParsedAttr::AT_CFReturnsNotRetained: - D->addAttr(::new (S.Context) CFReturnsNotRetainedAttr( - AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); + handleSimpleAttribute<CFReturnsNotRetainedAttr>(S, D, AL); return; case ParsedAttr::AT_NSReturnsNotRetained: - D->addAttr(::new (S.Context) NSReturnsNotRetainedAttr( - AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); + handleSimpleAttribute<NSReturnsNotRetainedAttr>(S, D, AL); return; case ParsedAttr::AT_CFReturnsRetained: - D->addAttr(::new (S.Context) CFReturnsRetainedAttr( - AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); + handleSimpleAttribute<CFReturnsRetainedAttr>(S, D, AL); return; case ParsedAttr::AT_NSReturnsRetained: - D->addAttr(::new (S.Context) NSReturnsRetainedAttr( - AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); + handleSimpleAttribute<NSReturnsRetainedAttr>(S, D, AL); + return; + case ParsedAttr::AT_OSReturnsRetained: + handleSimpleAttribute<OSReturnsRetainedAttr>(S, D, AL); + return; + case ParsedAttr::AT_OSReturnsNotRetained: + handleSimpleAttribute<OSReturnsNotRetainedAttr>(S, D, AL); return; }; } @@ -4829,11 +5020,10 @@ static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D, if (!resultType->isReferenceType() && (!resultType->isPointerType() || resultType->isObjCRetainableType())) { - S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_return_type) - << SourceRange(loc) - << Attrs.getName() - << (isa<ObjCMethodDecl>(D) ? EP_ObjCMethod : EP_ObjCProperty) - << /*non-retainable pointer*/ 2; + S.Diag(D->getBeginLoc(), diag::warn_ns_attribute_wrong_return_type) + << SourceRange(loc) << Attrs + << (isa<ObjCMethodDecl>(D) ? EP_ObjCMethod : EP_ObjCProperty) + << /*non-retainable pointer*/ 2; // Drop the attribute. return; @@ -4849,14 +5039,14 @@ static void handleObjCRequiresSuperAttr(Sema &S, Decl *D, const DeclContext *DC = Method->getDeclContext(); if (const auto *PDecl = dyn_cast_or_null<ObjCProtocolDecl>(DC)) { - S.Diag(D->getLocStart(), diag::warn_objc_requires_super_protocol) - << Attrs.getName() << 0; + S.Diag(D->getBeginLoc(), diag::warn_objc_requires_super_protocol) << Attrs + << 0; S.Diag(PDecl->getLocation(), diag::note_protocol_decl); return; } if (Method->getMethodFamily() == OMF_dealloc) { - S.Diag(D->getLocStart(), diag::warn_objc_requires_super_protocol) - << Attrs.getName() << 1; + S.Diag(D->getBeginLoc(), diag::warn_objc_requires_super_protocol) << Attrs + << 1; return; } @@ -4868,15 +5058,14 @@ static void handleObjCBridgeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { IdentifierLoc *Parm = AL.isArgIdent(0) ? AL.getArgAsIdent(0) : nullptr; if (!Parm) { - S.Diag(D->getLocStart(), diag::err_objc_attr_not_id) << AL.getName() << 0; + S.Diag(D->getBeginLoc(), diag::err_objc_attr_not_id) << AL << 0; return; } // Typedefs only allow objc_bridge(id) and have some additional checking. if (const auto *TD = dyn_cast<TypedefNameDecl>(D)) { if (!Parm->Ident->isStr("id")) { - S.Diag(AL.getLoc(), diag::err_objc_attr_typedef_not_id) - << AL.getName(); + S.Diag(AL.getLoc(), diag::err_objc_attr_typedef_not_id) << AL; return; } @@ -4898,7 +5087,7 @@ static void handleObjCBridgeMutableAttr(Sema &S, Decl *D, IdentifierLoc *Parm = AL.isArgIdent(0) ? AL.getArgAsIdent(0) : nullptr; if (!Parm) { - S.Diag(D->getLocStart(), diag::err_objc_attr_not_id) << AL.getName() << 0; + S.Diag(D->getBeginLoc(), diag::err_objc_attr_not_id) << AL << 0; return; } @@ -4912,7 +5101,7 @@ static void handleObjCBridgeRelatedAttr(Sema &S, Decl *D, IdentifierInfo *RelatedClass = AL.isArgIdent(0) ? AL.getArgAsIdent(0)->Ident : nullptr; if (!RelatedClass) { - S.Diag(D->getLocStart(), diag::err_objc_attr_not_id) << AL.getName() << 0; + S.Diag(D->getBeginLoc(), diag::err_objc_attr_not_id) << AL << 0; return; } IdentifierInfo *ClassMethod = @@ -4982,8 +5171,8 @@ static void handleObjCBoxable(Sema &S, Decl *D, const ParsedAttr &AL) { static void handleObjCOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (hasDeclarator(D)) return; - S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type) - << AL.getRange() << AL.getName() << ExpectedVariable; + S.Diag(D->getBeginLoc(), diag::err_attribute_wrong_decl_type) + << AL.getRange() << AL << ExpectedVariable; } static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D, @@ -5047,7 +5236,7 @@ UuidAttr *Sema::mergeUuidAttr(Decl *D, SourceRange Range, static void handleUuidAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!S.LangOpts.CPlusPlus) { S.Diag(AL.getLoc(), diag::err_attribute_not_supported_in_lang) - << AL.getName() << AttributeLangSupport::C; + << AL << AttributeLangSupport::C; return; } @@ -5097,7 +5286,7 @@ static void handleUuidAttr(Sema &S, Decl *D, const ParsedAttr &AL) { static void handleMSInheritanceAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!S.LangOpts.CPlusPlus) { S.Diag(AL.getLoc(), diag::err_attribute_not_supported_in_lang) - << AL.getName() << AttributeLangSupport::C; + << AL << AttributeLangSupport::C; return; } MSInheritanceAttr *IA = S.mergeMSInheritanceAttr( @@ -5152,7 +5341,7 @@ static void handleAbiTagAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; // Store tags sorted and without duplicates. - llvm::sort(Tags.begin(), Tags.end()); + llvm::sort(Tags); Tags.erase(std::unique(Tags.begin(), Tags.end()), Tags.end()); D->addAttr(::new (S.Context) @@ -5163,8 +5352,7 @@ static void handleAbiTagAttr(Sema &S, Decl *D, const ParsedAttr &AL) { static void handleARMInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Check the attribute arguments. if (AL.getNumArgs() > 1) { - S.Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) - << AL.getName() << 1; + S.Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) << AL << 1; return; } @@ -5178,8 +5366,8 @@ static void handleARMInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { ARMInterruptAttr::InterruptType Kind; if (!ARMInterruptAttr::ConvertStrToInterruptType(Str, Kind)) { - S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) - << AL.getName() << Str << ArgLoc; + S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << Str + << ArgLoc; return; } @@ -5193,8 +5381,8 @@ static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; if (!AL.isArgExpr(0)) { - S.Diag(AL.getLoc(), diag::err_attribute_argument_type) << AL.getName() - << AANT_ArgumentIntegerConstant; + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL << AANT_ArgumentIntegerConstant; return; } @@ -5204,16 +5392,16 @@ static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { llvm::APSInt NumParams(32); if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) { S.Diag(AL.getLoc(), diag::err_attribute_argument_type) - << AL.getName() << AANT_ArgumentIntegerConstant - << NumParamsExpr->getSourceRange(); + << AL << AANT_ArgumentIntegerConstant + << NumParamsExpr->getSourceRange(); return; } unsigned Num = NumParams.getLimitedValue(255); if ((Num & 1) || Num > 30) { S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) - << AL.getName() << (int)NumParams.getSExtValue() - << NumParamsExpr->getSourceRange(); + << AL << (int)NumParams.getSExtValue() + << NumParamsExpr->getSourceRange(); return; } @@ -5226,8 +5414,7 @@ static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { static void handleMipsInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Only one optional argument permitted. if (AL.getNumArgs() > 1) { - S.Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) - << AL.getName() << 1; + S.Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) << AL << 1; return; } @@ -5266,14 +5453,13 @@ static void handleMipsInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - if (checkAttrMutualExclusion<Mips16Attr>(S, D, AL.getRange(), - AL.getName())) + if (checkAttrMutualExclusion<Mips16Attr>(S, D, AL)) return; MipsInterruptAttr::InterruptType Kind; if (!MipsInterruptAttr::ConvertStrToInterruptType(Str, Kind)) { S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) - << AL.getName() << "'" + std::string(Str) + "'"; + << AL << "'" + std::string(Str) + "'"; return; } @@ -5292,7 +5478,7 @@ static void handleAnyX86InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { CXXMethodDecl::isStaticOverloadedOperator( cast<NamedDecl>(D)->getDeclName().getCXXOverloadedOperator())) { S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) - << AL.getName() << ExpectedFunctionWithProtoType; + << AL << ExpectedFunctionWithProtoType; return; } // Interrupt handler must have void return type. @@ -5308,7 +5494,7 @@ static void handleAnyX86InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Interrupt handler must have 1 or 2 parameters. unsigned NumParams = getFunctionOrMethodNumParams(D); if (NumParams < 1 || NumParams > 2) { - S.Diag(D->getLocStart(), diag::err_anyx86_interrupt_attribute) + S.Diag(D->getBeginLoc(), diag::err_anyx86_interrupt_attribute) << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86 ? 0 : 1) @@ -5421,8 +5607,8 @@ static void handleRISCVInterruptAttr(Sema &S, Decl *D, RISCVInterruptAttr::InterruptType Kind; if (!RISCVInterruptAttr::ConvertStrToInterruptType(Str, Kind)) { - S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) - << AL.getName() << Str << ArgLoc; + S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << Str + << ArgLoc; return; } @@ -5470,13 +5656,11 @@ static void handleAMDGPUFlatWorkGroupSizeAttr(Sema &S, Decl *D, return; if (Min == 0 && Max != 0) { - S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) - << AL.getName() << 0; + S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) << AL << 0; return; } if (Min > Max) { - S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) - << AL.getName() << 1; + S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) << AL << 1; return; } @@ -5499,13 +5683,11 @@ static void handleAMDGPUWavesPerEUAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } if (Min == 0 && Max != 0) { - S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) - << AL.getName() << 0; + S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) << AL << 0; return; } if (Max != 0 && Min > Max) { - S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) - << AL.getName() << 1; + S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) << AL << 1; return; } @@ -5552,7 +5734,7 @@ static void handleX86ForceAlignArgPointerAttr(Sema &S, Decl *D, // Attribute can only be applied to function types. if (!isa<FunctionDecl>(D)) { S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) - << AL.getName() << ExpectedFunction; + << AL << ExpectedFunction; return; } @@ -5568,12 +5750,17 @@ static void handleLayoutVersion(Sema &S, Decl *D, const ParsedAttr &AL) { return; // TODO: Investigate what happens with the next major version of MSVC. - if (Version != LangOptions::MSVC2015) { + if (Version != LangOptions::MSVC2015 / 100) { S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) - << AL.getName() << Version << VersionExpr->getSourceRange(); + << AL << Version << VersionExpr->getSourceRange(); return; } + // The attribute expects a "major" version number like 19, but new versions of + // MSVC have moved to updating the "minor", or less significant numbers, so we + // have to multiply by 100 now. + Version *= 100; + D->addAttr(::new (S.Context) LayoutVersionAttr(AL.getRange(), S.Context, Version, AL.getAttributeSpellingListIndex())); @@ -5608,8 +5795,7 @@ DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D, SourceRange Range, static void handleDLLAttr(Sema &S, Decl *D, const ParsedAttr &A) { if (isa<ClassTemplatePartialSpecializationDecl>(D) && S.Context.getTargetInfo().getCXXABI().isMicrosoft()) { - S.Diag(A.getRange().getBegin(), diag::warn_attribute_ignored) - << A.getName(); + S.Diag(A.getRange().getBegin(), diag::warn_attribute_ignored) << A; return; } @@ -5618,7 +5804,7 @@ static void handleDLLAttr(Sema &S, Decl *D, const ParsedAttr &A) { !S.Context.getTargetInfo().getCXXABI().isMicrosoft()) { // MinGW doesn't allow dllimport on inline functions. S.Diag(A.getRange().getBegin(), diag::warn_attribute_ignored_on_inline) - << A.getName(); + << A; return; } } @@ -5626,7 +5812,7 @@ static void handleDLLAttr(Sema &S, Decl *D, const ParsedAttr &A) { if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) { if (S.Context.getTargetInfo().getCXXABI().isMicrosoft() && MD->getParent()->isLambda()) { - S.Diag(A.getRange().getBegin(), diag::err_attribute_dll_lambda) << A.getName(); + S.Diag(A.getRange().getBegin(), diag::err_attribute_dll_lambda) << A; return; } } @@ -5788,10 +5974,8 @@ static void handleDeprecatedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { !S.checkStringLiteralArgumentAttr(AL, 1, Replacement)) return; - if (!S.getLangOpts().CPlusPlus14) - if (AL.isCXX11Attribute() && - !(AL.hasScope() && AL.getScopeName()->isStr("gnu"))) - S.Diag(AL.getLoc(), diag::ext_cxx14_attr) << AL.getName(); + if (!S.getLangOpts().CPlusPlus14 && AL.isCXX11Attribute() && !AL.isGNUScope()) + S.Diag(AL.getLoc(), diag::ext_cxx14_attr) << AL; D->addAttr(::new (S.Context) DeprecatedAttr(AL.getRange(), S.Context, Str, Replacement, @@ -5821,7 +6005,7 @@ static void handleNoSanitizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { S.Diag(LiteralLoc, diag::warn_unknown_sanitizer_ignored) << SanitizerName; else if (isGlobalVar(D) && SanitizerName != "address") S.Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) - << AL.getName() << ExpectedFunctionOrMethod; + << AL << ExpectedFunctionOrMethod; Sanitizers.push_back(SanitizerName); } @@ -5841,26 +6025,24 @@ static void handleNoSanitizeSpecificAttr(Sema &S, Decl *D, .Case("no_sanitize_memory", "memory"); if (isGlobalVar(D) && SanitizerName != "address") S.Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) - << AL.getName() << ExpectedFunction; + << AL << ExpectedFunction; D->addAttr(::new (S.Context) NoSanitizeAttr(AL.getRange(), S.Context, &SanitizerName, 1, AL.getAttributeSpellingListIndex())); } static void handleInternalLinkageAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (InternalLinkageAttr *Internal = - S.mergeInternalLinkageAttr(D, AL.getRange(), AL.getName(), - AL.getAttributeSpellingListIndex())) + if (InternalLinkageAttr *Internal = S.mergeInternalLinkageAttr(D, AL)) D->addAttr(Internal); } static void handleOpenCLNoSVMAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (S.LangOpts.OpenCLVersion != 200) S.Diag(AL.getLoc(), diag::err_attribute_requires_opencl_version) - << AL.getName() << "2.0" << 0; + << AL << "2.0" << 0; else - S.Diag(AL.getLoc(), diag::warn_opencl_attr_deprecated_ignored) - << AL.getName() << "2.0"; + S.Diag(AL.getLoc(), diag::warn_opencl_attr_deprecated_ignored) << AL + << "2.0"; } /// Handles semantic checking for features that are common to all attributes, @@ -5912,10 +6094,16 @@ static void handleOpenCLAccessAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Check if there is only one access qualifier. if (D->hasAttr<OpenCLAccessAttr>()) { - S.Diag(AL.getLoc(), diag::err_opencl_multiple_access_qualifiers) - << D->getSourceRange(); - D->setInvalidDecl(true); - return; + if (D->getAttr<OpenCLAccessAttr>()->getSemanticSpelling() == + AL.getSemanticSpelling()) { + S.Diag(AL.getLoc(), diag::warn_duplicate_declspec) + << AL.getName()->getName() << AL.getRange(); + } else { + S.Diag(AL.getLoc(), diag::err_opencl_multiple_access_qualifiers) + << D->getSourceRange(); + D->setInvalidDecl(true); + return; + } } // OpenCL v2.0 s6.6 - read_write can be used for image types to specify that an @@ -5928,7 +6116,7 @@ static void handleOpenCLAccessAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (AL.getName()->getName().find("read_write") != StringRef::npos) { if (S.getLangOpts().OpenCLVersion < 200 || DeclTy->isPipeType()) { S.Diag(AL.getLoc(), diag::err_opencl_invalid_read_write) - << AL.getName() << PDecl->getType() << DeclTy->isImageType(); + << AL << PDecl->getType() << DeclTy->isImageType(); D->setInvalidDecl(true); return; } @@ -5939,6 +6127,100 @@ static void handleOpenCLAccessAttr(Sema &S, Decl *D, const ParsedAttr &AL) { AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); } +static void handleDestroyAttr(Sema &S, Decl *D, const ParsedAttr &A) { + if (!cast<VarDecl>(D)->hasGlobalStorage()) { + S.Diag(D->getLocation(), diag::err_destroy_attr_on_non_static_var) + << (A.getKind() == ParsedAttr::AT_AlwaysDestroy); + return; + } + + if (A.getKind() == ParsedAttr::AT_AlwaysDestroy) + handleSimpleAttributeWithExclusions<AlwaysDestroyAttr, NoDestroyAttr>(S, D, A); + else + handleSimpleAttributeWithExclusions<NoDestroyAttr, AlwaysDestroyAttr>(S, D, A); +} + +static void handleUninitializedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + assert(cast<VarDecl>(D)->getStorageDuration() == SD_Automatic && + "uninitialized is only valid on automatic duration variables"); + unsigned Index = AL.getAttributeSpellingListIndex(); + D->addAttr(::new (S.Context) + UninitializedAttr(AL.getLoc(), S.Context, Index)); +} + +static bool tryMakeVariablePseudoStrong(Sema &S, VarDecl *VD, + bool DiagnoseFailure) { + QualType Ty = VD->getType(); + if (!Ty->isObjCRetainableType()) { + if (DiagnoseFailure) { + S.Diag(VD->getBeginLoc(), diag::warn_ignored_objc_externally_retained) + << 0; + } + return false; + } + + Qualifiers::ObjCLifetime LifetimeQual = Ty.getQualifiers().getObjCLifetime(); + + // Sema::inferObjCARCLifetime must run after processing decl attributes + // (because __block lowers to an attribute), so if the lifetime hasn't been + // explicitly specified, infer it locally now. + if (LifetimeQual == Qualifiers::OCL_None) + LifetimeQual = Ty->getObjCARCImplicitLifetime(); + + // The attributes only really makes sense for __strong variables; ignore any + // attempts to annotate a parameter with any other lifetime qualifier. + if (LifetimeQual != Qualifiers::OCL_Strong) { + if (DiagnoseFailure) { + S.Diag(VD->getBeginLoc(), diag::warn_ignored_objc_externally_retained) + << 1; + } + return false; + } + + // Tampering with the type of a VarDecl here is a bit of a hack, but we need + // to ensure that the variable is 'const' so that we can error on + // modification, which can otherwise over-release. + VD->setType(Ty.withConst()); + VD->setARCPseudoStrong(true); + return true; +} + +static void handleObjCExternallyRetainedAttr(Sema &S, Decl *D, + const ParsedAttr &AL) { + if (auto *VD = dyn_cast<VarDecl>(D)) { + assert(!isa<ParmVarDecl>(VD) && "should be diagnosed automatically"); + if (!VD->hasLocalStorage()) { + S.Diag(D->getBeginLoc(), diag::warn_ignored_objc_externally_retained) + << 0; + return; + } + + if (!tryMakeVariablePseudoStrong(S, VD, /*DiagnoseFailure=*/true)) + return; + + handleSimpleAttribute<ObjCExternallyRetainedAttr>(S, D, AL); + return; + } + + // If D is a function-like declaration (method, block, or function), then we + // make every parameter psuedo-strong. + for (unsigned I = 0, E = getFunctionOrMethodNumParams(D); I != E; ++I) { + auto *PVD = const_cast<ParmVarDecl *>(getFunctionOrMethodParam(D, I)); + QualType Ty = PVD->getType(); + + // If a user wrote a parameter with __strong explicitly, then assume they + // want "real" strong semantics for that parameter. This works because if + // the parameter was written with __strong, then the strong qualifier will + // be non-local. + if (Ty.getLocalUnqualifiedType().getQualifiers().getObjCLifetime() == + Qualifiers::OCL_Strong) + continue; + + tryMakeVariablePseudoStrong(S, PVD, /*DiagnoseFailure=*/false); + } + handleSimpleAttribute<ObjCExternallyRetainedAttr>(S, D, AL); +} + //===----------------------------------------------------------------------===// // Top Level Sema Entry Points //===----------------------------------------------------------------------===// @@ -5962,10 +6244,11 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, // though they were unknown attributes. if (AL.getKind() == ParsedAttr::UnknownAttribute || !AL.existsInTarget(S.Context.getTargetInfo())) { - S.Diag(AL.getLoc(), AL.isDeclspecAttribute() - ? diag::warn_unhandled_ms_attribute_ignored - : diag::warn_unknown_attribute_ignored) - << AL.getName(); + S.Diag(AL.getLoc(), + AL.isDeclspecAttribute() + ? (unsigned)diag::warn_unhandled_ms_attribute_ignored + : (unsigned)diag::warn_unknown_attribute_ignored) + << AL; return; } @@ -5980,7 +6263,7 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, break; } S.Diag(AL.getLoc(), diag::err_stmt_attribute_invalid_on_decl) - << AL.getName() << D->getLocation(); + << AL << D->getLocation(); break; case ParsedAttr::AT_Interrupt: handleInterruptAttr(S, D, AL); @@ -6259,17 +6542,37 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, break; case ParsedAttr::AT_CFConsumed: case ParsedAttr::AT_NSConsumed: - handleNSConsumedAttr(S, D, AL); + case ParsedAttr::AT_OSConsumed: + S.AddXConsumedAttr(D, AL.getRange(), AL.getAttributeSpellingListIndex(), + parsedAttrToRetainOwnershipKind(AL), + /*IsTemplateInstantiation=*/false); break; case ParsedAttr::AT_NSConsumesSelf: handleSimpleAttribute<NSConsumesSelfAttr>(S, D, AL); break; + case ParsedAttr::AT_OSConsumesThis: + handleSimpleAttribute<OSConsumesThisAttr>(S, D, AL); + break; + case ParsedAttr::AT_OSReturnsRetainedOnZero: + handleSimpleAttributeOrDiagnose<OSReturnsRetainedOnZeroAttr>( + S, D, AL, isValidOSObjectOutParameter(D), + diag::warn_ns_attribute_wrong_parameter_type, + /*Extra Args=*/AL, /*pointer-to-OSObject-pointer*/ 3, AL.getRange()); + break; + case ParsedAttr::AT_OSReturnsRetainedOnNonZero: + handleSimpleAttributeOrDiagnose<OSReturnsRetainedOnNonZeroAttr>( + S, D, AL, isValidOSObjectOutParameter(D), + diag::warn_ns_attribute_wrong_parameter_type, + /*Extra Args=*/AL, /*pointer-to-OSObject-poointer*/ 3, AL.getRange()); + break; case ParsedAttr::AT_NSReturnsAutoreleased: case ParsedAttr::AT_NSReturnsNotRetained: - case ParsedAttr::AT_CFReturnsNotRetained: case ParsedAttr::AT_NSReturnsRetained: + case ParsedAttr::AT_CFReturnsNotRetained: case ParsedAttr::AT_CFReturnsRetained: - handleNSReturnsRetainedAttr(S, D, AL); + case ParsedAttr::AT_OSReturnsNotRetained: + case ParsedAttr::AT_OSReturnsRetained: + handleXReturnsXRetainedAttr(S, D, AL); break; case ParsedAttr::AT_WorkGroupSizeHint: handleWorkGroupSize<WorkGroupSizeHintAttr>(S, D, AL); @@ -6295,6 +6598,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_Section: handleSectionAttr(S, D, AL); break; + case ParsedAttr::AT_SpeculativeLoadHardening: + handleSimpleAttribute<SpeculativeLoadHardeningAttr>(S, D, AL); + break; case ParsedAttr::AT_CodeSeg: handleCodeSegAttr(S, D, AL); break; @@ -6423,6 +6729,7 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_IntelOclBicc: case ParsedAttr::AT_PreserveMost: case ParsedAttr::AT_PreserveAll: + case ParsedAttr::AT_AArch64VectorPcs: handleCallConvAttr(S, D, AL); break; case ParsedAttr::AT_Suppress: @@ -6449,6 +6756,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_InternalLinkage: handleInternalLinkageAttr(S, D, AL); break; + case ParsedAttr::AT_ExcludeFromExplicitInstantiation: + handleSimpleAttribute<ExcludeFromExplicitInstantiationAttr>(S, D, AL); + break; case ParsedAttr::AT_LTOVisibilityPublic: handleSimpleAttribute<LTOVisibilityPublicAttr>(S, D, AL); break; @@ -6604,6 +6914,24 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_XRayLogArgs: handleXRayLogArgsAttr(S, D, AL); break; + + // Move semantics attribute. + case ParsedAttr::AT_Reinitializes: + handleSimpleAttribute<ReinitializesAttr>(S, D, AL); + break; + + case ParsedAttr::AT_AlwaysDestroy: + case ParsedAttr::AT_NoDestroy: + handleDestroyAttr(S, D, AL); + break; + + case ParsedAttr::AT_Uninitialized: + handleUninitializedAttr(S, D, AL); + break; + + case ParsedAttr::AT_ObjCExternallyRetained: + handleObjCExternallyRetainedAttr(S, D, AL); + break; } } @@ -6708,10 +7036,10 @@ static void checkUnusedDeclAttributes(Sema &S, const ParsedAttributesView &A) { if (AL.getKind() == ParsedAttr::UnknownAttribute) { S.Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) - << AL.getName() << AL.getRange(); + << AL << AL.getRange(); } else { - S.Diag(AL.getLoc(), diag::warn_attribute_not_on_decl) - << AL.getName() << AL.getRange(); + S.Diag(AL.getLoc(), diag::warn_attribute_not_on_decl) << AL + << AL.getRange(); } } } @@ -6942,8 +7270,12 @@ static const AvailabilityAttr *getAttrForPlatform(ASTContext &Context, /// \param D The declaration to check. /// \param Message If non-null, this will be populated with the message from /// the availability attribute that is selected. +/// \param ClassReceiver If we're checking the the method of a class message +/// send, the class. Otherwise nullptr. static std::pair<AvailabilityResult, const NamedDecl *> -ShouldDiagnoseAvailabilityOfDecl(const NamedDecl *D, std::string *Message) { +ShouldDiagnoseAvailabilityOfDecl(Sema &S, const NamedDecl *D, + std::string *Message, + ObjCInterfaceDecl *ClassReceiver) { AvailabilityResult Result = D->getAvailability(Message); // For typedefs, if the typedef declaration appears available look @@ -6976,6 +7308,20 @@ ShouldDiagnoseAvailabilityOfDecl(const NamedDecl *D, std::string *Message) { } } + // For +new, infer availability from -init. + if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { + if (S.NSAPIObj && ClassReceiver) { + ObjCMethodDecl *Init = ClassReceiver->lookupInstanceMethod( + S.NSAPIObj->getInitSelector()); + if (Init && Result == AR_Available && MD->isClassMethod() && + MD->getSelector() == S.NSAPIObj->getNewSelector() && + MD->definedInNSObject(S.getASTContext())) { + Result = Init->getAvailability(Message); + D = Init; + } + } + } + return {Result, D}; } @@ -6983,9 +7329,10 @@ ShouldDiagnoseAvailabilityOfDecl(const NamedDecl *D, std::string *Message) { /// whether we should emit a diagnostic for \c K and \c DeclVersion in /// the context of \c Ctx. For example, we should emit an unavailable diagnostic /// in a deprecated context, but not the other way around. -static bool ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K, - VersionTuple DeclVersion, - Decl *Ctx) { +static bool +ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K, + VersionTuple DeclVersion, Decl *Ctx, + const NamedDecl *OffendingDecl) { assert(K != AR_Available && "Expected an unavailable declaration here!"); // Checks if we should emit the availability diagnostic in the context of C. @@ -6994,9 +7341,22 @@ static bool ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K, if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, C)) if (AA->getIntroduced() >= DeclVersion) return true; - } else if (K == AR_Deprecated) + } else if (K == AR_Deprecated) { if (C->isDeprecated()) return true; + } else if (K == AR_Unavailable) { + // It is perfectly fine to refer to an 'unavailable' Objective-C method + // when it's actually defined and is referenced from within the + // @implementation itself. In this context, we interpret unavailable as a + // form of access control. + if (const auto *MD = dyn_cast<ObjCMethodDecl>(OffendingDecl)) { + if (const auto *Impl = dyn_cast<ObjCImplDecl>(C)) { + if (MD->getClassInterface() == Impl->getClassInterface() && + MD->isDefined()) + return true; + } + } + } if (C->isUnavailable()) return true; @@ -7078,13 +7438,13 @@ struct AttributeInsertion { StringRef Suffix; static AttributeInsertion createInsertionAfter(const NamedDecl *D) { - return {" ", D->getLocEnd(), ""}; + return {" ", D->getEndLoc(), ""}; } static AttributeInsertion createInsertionAfter(SourceLocation Loc) { return {" ", Loc, ""}; } static AttributeInsertion createInsertionBefore(const NamedDecl *D) { - return {"", D->getLocStart(), "\n"}; + return {"", D->getBeginLoc(), "\n"}; } }; @@ -7185,7 +7545,8 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, OffendingDecl)) DeclVersion = AA->getIntroduced(); - if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, Ctx)) + if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, Ctx, + OffendingDecl)) return; SourceLocation Loc = Locs.front(); @@ -7223,14 +7584,16 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, unsigned Warning = UseNewWarning ? diag::warn_unguarded_availability_new : diag::warn_unguarded_availability; - S.Diag(Loc, Warning) - << OffendingDecl - << AvailabilityAttr::getPrettyPlatformName( - S.getASTContext().getTargetInfo().getPlatformName()) - << Introduced.getAsString(); + std::string PlatformName = AvailabilityAttr::getPrettyPlatformName( + S.getASTContext().getTargetInfo().getPlatformName()); - S.Diag(OffendingDecl->getLocation(), diag::note_availability_specified_here) - << OffendingDecl << /* partial */ 3; + S.Diag(Loc, Warning) << OffendingDecl << PlatformName + << Introduced.getAsString(); + + S.Diag(OffendingDecl->getLocation(), + diag::note_partial_availability_specified_here) + << OffendingDecl << PlatformName << Introduced.getAsString() + << S.Context.getTargetInfo().getPlatformMinVersion().getAsString(); if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) { if (const auto *TD = dyn_cast<TagDecl>(Enclosing)) @@ -7423,6 +7786,7 @@ void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) { // for each of the different declarations. const DelayedDiagnosticPool *pool = &poppedPool; do { + bool AnyAccessFailures = false; for (DelayedDiagnosticPool::pool_iterator i = pool->pool_begin(), e = pool->pool_end(); i != e; ++i) { // This const_cast is a bit lame. Really, Triggered should be mutable. @@ -7439,7 +7803,14 @@ void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) { break; case DelayedDiagnostic::Access: + // Only produce one access control diagnostic for a structured binding + // declaration: we don't need to tell the user that all the fields are + // inaccessible one at a time. + if (AnyAccessFailures && isa<DecompositionDecl>(decl)) + continue; HandleDelayedAccessCheck(diag, decl); + if (diag.Triggered) + AnyAccessFailures = true; break; case DelayedDiagnostic::ForbiddenType: @@ -7564,7 +7935,8 @@ class DiagnoseUnguardedAvailability SmallVector<VersionTuple, 8> AvailabilityStack; SmallVector<const Stmt *, 16> StmtStack; - void DiagnoseDeclAvailability(NamedDecl *D, SourceRange Range); + void DiagnoseDeclAvailability(NamedDecl *D, SourceRange Range, + ObjCInterfaceDecl *ClassReceiver = nullptr); public: DiagnoseUnguardedAvailability(Sema &SemaRef, Decl *Ctx) @@ -7606,27 +7978,33 @@ public: } bool VisitObjCMessageExpr(ObjCMessageExpr *Msg) { - if (ObjCMethodDecl *D = Msg->getMethodDecl()) + if (ObjCMethodDecl *D = Msg->getMethodDecl()) { + ObjCInterfaceDecl *ID = nullptr; + QualType ReceiverTy = Msg->getClassReceiver(); + if (!ReceiverTy.isNull() && ReceiverTy->getAsObjCInterfaceType()) + ID = ReceiverTy->getAsObjCInterfaceType()->getInterface(); + DiagnoseDeclAvailability( - D, SourceRange(Msg->getSelectorStartLoc(), Msg->getLocEnd())); + D, SourceRange(Msg->getSelectorStartLoc(), Msg->getEndLoc()), ID); + } return true; } bool VisitDeclRefExpr(DeclRefExpr *DRE) { DiagnoseDeclAvailability(DRE->getDecl(), - SourceRange(DRE->getLocStart(), DRE->getLocEnd())); + SourceRange(DRE->getBeginLoc(), DRE->getEndLoc())); return true; } bool VisitMemberExpr(MemberExpr *ME) { DiagnoseDeclAvailability(ME->getMemberDecl(), - SourceRange(ME->getLocStart(), ME->getLocEnd())); + SourceRange(ME->getBeginLoc(), ME->getEndLoc())); return true; } bool VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) { - SemaRef.Diag(E->getLocStart(), diag::warn_at_available_unchecked_use) - << (!SemaRef.getLangOpts().ObjC1); + SemaRef.Diag(E->getBeginLoc(), diag::warn_at_available_unchecked_use) + << (!SemaRef.getLangOpts().ObjC); return true; } @@ -7634,11 +8012,11 @@ public: }; void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability( - NamedDecl *D, SourceRange Range) { + NamedDecl *D, SourceRange Range, ObjCInterfaceDecl *ReceiverClass) { AvailabilityResult Result; const NamedDecl *OffendingDecl; std::tie(Result, OffendingDecl) = - ShouldDiagnoseAvailabilityOfDecl(D, nullptr); + ShouldDiagnoseAvailabilityOfDecl(SemaRef, D, nullptr, ReceiverClass); if (Result != AR_Available) { // All other diagnostic kinds have already been handled in // DiagnoseAvailabilityOfDecl. @@ -7654,7 +8032,8 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability( // If the context of this function is less available than D, we should not // emit a diagnostic. - if (!ShouldDiagnoseAvailabilityInContext(SemaRef, Result, Introduced, Ctx)) + if (!ShouldDiagnoseAvailabilityInContext(SemaRef, Result, Introduced, Ctx, + OffendingDecl)) return; // We would like to emit the diagnostic even if -Wunguarded-availability is @@ -7668,21 +8047,24 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability( ? diag::warn_unguarded_availability_new : diag::warn_unguarded_availability; + std::string PlatformName = AvailabilityAttr::getPrettyPlatformName( + SemaRef.getASTContext().getTargetInfo().getPlatformName()); + SemaRef.Diag(Range.getBegin(), DiagKind) - << Range << D - << AvailabilityAttr::getPrettyPlatformName( - SemaRef.getASTContext().getTargetInfo().getPlatformName()) - << Introduced.getAsString(); + << Range << D << PlatformName << Introduced.getAsString(); SemaRef.Diag(OffendingDecl->getLocation(), - diag::note_availability_specified_here) - << OffendingDecl << /* partial */ 3; + diag::note_partial_availability_specified_here) + << OffendingDecl << PlatformName << Introduced.getAsString() + << SemaRef.Context.getTargetInfo() + .getPlatformMinVersion() + .getAsString(); auto FixitDiag = SemaRef.Diag(Range.getBegin(), diag::note_unguarded_available_silence) << Range << D - << (SemaRef.getLangOpts().ObjC1 ? /*@available*/ 0 - : /*__builtin_available*/ 1); + << (SemaRef.getLangOpts().ObjC ? /*@available*/ 0 + : /*__builtin_available*/ 1); // Find the statement which should be enclosed in the if @available check. if (StmtStack.empty()) @@ -7714,10 +8096,10 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability( const SourceManager &SM = SemaRef.getSourceManager(); SourceLocation IfInsertionLoc = - SM.getExpansionLoc(StmtOfUse->getLocStart()); + SM.getExpansionLoc(StmtOfUse->getBeginLoc()); SourceLocation StmtEndLoc = SM.getExpansionRange( - (LastStmtOfUse ? LastStmtOfUse : StmtOfUse)->getLocEnd()) + (LastStmtOfUse ? LastStmtOfUse : StmtOfUse)->getEndLoc()) .getEnd(); if (SM.getFileID(IfInsertionLoc) != SM.getFileID(StmtEndLoc)) return; @@ -7726,8 +8108,8 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability( const char *ExtraIndentation = " "; std::string FixItString; llvm::raw_string_ostream FixItOS(FixItString); - FixItOS << "if (" << (SemaRef.getLangOpts().ObjC1 ? "@available" - : "__builtin_available") + FixItOS << "if (" << (SemaRef.getLangOpts().ObjC ? "@available" + : "__builtin_available") << "(" << AvailabilityAttr::getPlatformNameSourceSpelling( SemaRef.getASTContext().getTargetInfo().getPlatformName()) @@ -7820,12 +8202,14 @@ void Sema::DiagnoseAvailabilityOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs, const ObjCInterfaceDecl *UnknownObjCClass, bool ObjCPropertyAccess, - bool AvoidPartialAvailabilityChecks) { + bool AvoidPartialAvailabilityChecks, + ObjCInterfaceDecl *ClassReceiver) { std::string Message; AvailabilityResult Result; const NamedDecl* OffendingDecl; // See if this declaration is unavailable, deprecated, or partial. - std::tie(Result, OffendingDecl) = ShouldDiagnoseAvailabilityOfDecl(D, &Message); + std::tie(Result, OffendingDecl) = + ShouldDiagnoseAvailabilityOfDecl(*this, D, &Message, ClassReceiver); if (Result == AR_Available) return; |