diff options
Diffstat (limited to 'lib/Sema/SemaDeclAttr.cpp')
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 308 |
1 files changed, 272 insertions, 36 deletions
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index c6a5bc74145c..a1ba9de368db 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -218,21 +218,45 @@ static bool checkAttributeAtMostNumArgs(Sema &S, const AttributeList &Attr, std::greater<unsigned>()); } +/// \brief A helper function to provide Attribute Location for the Attr types +/// AND the AttributeList. +template <typename AttrInfo> +static typename std::enable_if<std::is_base_of<clang::Attr, AttrInfo>::value, + SourceLocation>::type +getAttrLoc(const AttrInfo &Attr) { + return Attr.getLocation(); +} +static SourceLocation getAttrLoc(const clang::AttributeList &Attr) { + return Attr.getLoc(); +} + +/// \brief A helper function to provide Attribute Name for the Attr types +/// AND the AttributeList. +template <typename AttrInfo> +static typename std::enable_if<std::is_base_of<clang::Attr, AttrInfo>::value, + const AttrInfo *>::type +getAttrName(const AttrInfo &Attr) { + return &Attr; +} +const IdentifierInfo *getAttrName(const clang::AttributeList &Attr) { + return Attr.getName(); +} + /// \brief If Expr is a valid integer constant, get the value of the integer /// expression and return success or failure. May output an error. -static bool checkUInt32Argument(Sema &S, const AttributeList &Attr, - const Expr *Expr, uint32_t &Val, - unsigned Idx = UINT_MAX) { +template<typename AttrInfo> +static bool checkUInt32Argument(Sema &S, const AttrInfo& Attr, const Expr *Expr, + uint32_t &Val, unsigned Idx = UINT_MAX) { llvm::APSInt I(32); if (Expr->isTypeDependent() || Expr->isValueDependent() || !Expr->isIntegerConstantExpr(I, S.Context)) { if (Idx != UINT_MAX) - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) - << Attr.getName() << Idx << AANT_ArgumentIntegerConstant + S.Diag(getAttrLoc(Attr), diag::err_attribute_argument_n_type) + << getAttrName(Attr) << Idx << AANT_ArgumentIntegerConstant << Expr->getSourceRange(); else - S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) - << Attr.getName() << AANT_ArgumentIntegerConstant + S.Diag(getAttrLoc(Attr), diag::err_attribute_argument_type) + << getAttrName(Attr) << AANT_ArgumentIntegerConstant << Expr->getSourceRange(); return false; } @@ -250,9 +274,9 @@ static bool checkUInt32Argument(Sema &S, const AttributeList &Attr, /// \brief Wrapper around checkUInt32Argument, with an extra check to be sure /// that the result will fit into a regular (signed) int. All args have the same /// purpose as they do in checkUInt32Argument. -static bool checkPositiveIntArgument(Sema &S, const AttributeList &Attr, - const Expr *Expr, int &Val, - unsigned Idx = UINT_MAX) { +template<typename AttrInfo> +static bool checkPositiveIntArgument(Sema &S, const AttrInfo& Attr, const Expr *Expr, + int &Val, unsigned Idx = UINT_MAX) { uint32_t UVal; if (!checkUInt32Argument(S, Attr, Expr, UVal, Idx)) return false; @@ -287,11 +311,10 @@ static bool checkAttrMutualExclusion(Sema &S, Decl *D, SourceRange Range, /// instance method D. May output an error. /// /// \returns true if IdxExpr is a valid index. -static bool checkFunctionOrMethodParameterIndex(Sema &S, const Decl *D, - const AttributeList &Attr, - unsigned AttrArgNum, - const Expr *IdxExpr, - uint64_t &Idx) { +template <typename AttrInfo> +static bool checkFunctionOrMethodParameterIndex( + Sema &S, const Decl *D, const AttrInfo& Attr, + unsigned AttrArgNum, const Expr *IdxExpr, uint64_t &Idx) { assert(isFunctionOrMethodOrBlock(D)); // In C++ the implicit 'this' function parameter also counts. @@ -305,24 +328,24 @@ static bool checkFunctionOrMethodParameterIndex(Sema &S, const Decl *D, llvm::APSInt IdxInt; if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() || !IdxExpr->isIntegerConstantExpr(IdxInt, S.Context)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) - << Attr.getName() << AttrArgNum << AANT_ArgumentIntegerConstant + S.Diag(getAttrLoc(Attr), diag::err_attribute_argument_n_type) + << getAttrName(Attr) << AttrArgNum << AANT_ArgumentIntegerConstant << IdxExpr->getSourceRange(); return false; } Idx = IdxInt.getLimitedValue(); if (Idx < 1 || (!IV && Idx > NumParams)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds) - << Attr.getName() << AttrArgNum << IdxExpr->getSourceRange(); + S.Diag(getAttrLoc(Attr), diag::err_attribute_argument_out_of_bounds) + << getAttrName(Attr) << AttrArgNum << IdxExpr->getSourceRange(); return false; } Idx--; // Convert to zero-based. if (HasImplicitThisParam) { if (Idx == 0) { - S.Diag(Attr.getLoc(), + S.Diag(getAttrLoc(Attr), diag::err_attribute_invalid_implicit_this_argument) - << Attr.getName() << IdxExpr->getSourceRange(); + << getAttrName(Attr) << IdxExpr->getSourceRange(); return false; } --Idx; @@ -753,31 +776,48 @@ static void handleAssertExclusiveLockAttr(Sema &S, Decl *D, Attr.getAttributeSpellingListIndex())); } -/// \brief Checks to be sure that the given parameter number is inbounds, and is -/// an some integral type. Will emit appropriate diagnostics if this returns +/// \brief Checks to be sure that the given parameter number is in bounds, and is +/// an integral type. Will emit appropriate diagnostics if this returns /// false. /// /// FuncParamNo is expected to be from the user, so is base-1. AttrArgNo is used /// to actually retrieve the argument, so it's base-0. +template <typename AttrInfo> static bool checkParamIsIntegerType(Sema &S, const FunctionDecl *FD, - const AttributeList &Attr, - unsigned FuncParamNo, unsigned AttrArgNo) { - assert(Attr.isArgExpr(AttrArgNo) && "Expected expression argument"); + const AttrInfo &Attr, Expr *AttrArg, + unsigned FuncParamNo, unsigned AttrArgNo, + bool AllowDependentType = false) { uint64_t Idx; - if (!checkFunctionOrMethodParameterIndex(S, FD, Attr, FuncParamNo, - Attr.getArgAsExpr(AttrArgNo), Idx)) + if (!checkFunctionOrMethodParameterIndex(S, FD, Attr, FuncParamNo, AttrArg, + Idx)) return false; const ParmVarDecl *Param = FD->getParamDecl(Idx); + if (AllowDependentType && Param->getType()->isDependentType()) + return true; if (!Param->getType()->isIntegerType() && !Param->getType()->isCharType()) { - SourceLocation SrcLoc = Attr.getArgAsExpr(AttrArgNo)->getLocStart(); + SourceLocation SrcLoc = AttrArg->getLocStart(); S.Diag(SrcLoc, diag::err_attribute_integers_only) - << Attr.getName() << Param->getSourceRange(); + << getAttrName(Attr) << Param->getSourceRange(); return false; } return true; } +/// \brief Checks to be sure that the given parameter number is in bounds, and is +/// an integral type. Will emit appropriate diagnostics if this returns false. +/// +/// FuncParamNo is expected to be from the user, so is base-1. AttrArgNo is used +/// to actually retrieve the argument, so it's base-0. +static bool checkParamIsIntegerType(Sema &S, const FunctionDecl *FD, + const AttributeList &Attr, + unsigned FuncParamNo, unsigned AttrArgNo, + bool AllowDependentType = false) { + assert(Attr.isArgExpr(AttrArgNo) && "Expected expression argument"); + return checkParamIsIntegerType(S, FD, Attr, Attr.getArgAsExpr(AttrArgNo), + FuncParamNo, AttrArgNo, AllowDependentType); +} + static void handleAllocSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!checkAttributeAtLeastNumArgs(S, Attr, 1) || !checkAttributeAtMostNumArgs(S, Attr, 2)) @@ -792,7 +832,7 @@ static void handleAllocSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) { const Expr *SizeExpr = Attr.getArgAsExpr(0); int SizeArgNo; - // Paramater indices are 1-indexed, hence Index=1 + // Parameter indices are 1-indexed, hence Index=1 if (!checkPositiveIntArgument(S, Attr, SizeExpr, SizeArgNo, /*Index=*/1)) return; @@ -803,7 +843,7 @@ static void handleAllocSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) { int NumberArgNo = 0; if (Attr.getNumArgs() == 2) { const Expr *NumberExpr = Attr.getArgAsExpr(1); - // Paramater indices are 1-based, hence Index=2 + // Parameter indices are 1-based, hence Index=2 if (!checkPositiveIntArgument(S, Attr, NumberExpr, NumberArgNo, /*Index=*/2)) return; @@ -1420,7 +1460,7 @@ static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) { // check if the attribute came from a macro expansion or a template // instantiation. if (NonNullArgs.empty() && Attr.getLoc().isFileID() && - S.ActiveTemplateInstantiations.empty()) { + !S.inTemplateInstantiation()) { bool AnyPointers = isFunctionOrMethodVariadic(D); for (unsigned I = 0, E = getFunctionOrMethodNumParams(D); I != E && !AnyPointers; ++I) { @@ -1484,6 +1524,12 @@ static void handleAssumeAlignedAttr(Sema &S, Decl *D, Attr.getAttributeSpellingListIndex()); } +static void handleAllocAlignAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + S.AddAllocAlignAttr(Attr.getRange(), D, Attr.getArgAsExpr(0), + Attr.getAttributeSpellingListIndex()); +} + void Sema::AddAssumeAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, Expr *OE, unsigned SpellingListIndex) { QualType ResultType = getFunctionOrMethodResultType(D); @@ -1535,6 +1581,44 @@ void Sema::AddAssumeAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, AssumeAlignedAttr(AttrRange, Context, E, OE, SpellingListIndex)); } +void Sema::AddAllocAlignAttr(SourceRange AttrRange, Decl *D, Expr *ParamExpr, + unsigned SpellingListIndex) { + QualType ResultType = getFunctionOrMethodResultType(D); + + AllocAlignAttr TmpAttr(AttrRange, Context, 0, SpellingListIndex); + SourceLocation AttrLoc = AttrRange.getBegin(); + + if (!ResultType->isDependentType() && + !isValidPointerAttrType(ResultType, /* RefOkay */ true)) { + Diag(AttrLoc, diag::warn_attribute_return_pointers_refs_only) + << &TmpAttr << AttrRange << getFunctionOrMethodResultSourceRange(D); + return; + } + + uint64_t IndexVal; + const auto *FuncDecl = cast<FunctionDecl>(D); + if (!checkFunctionOrMethodParameterIndex(*this, FuncDecl, TmpAttr, + /*AttrArgNo=*/1, ParamExpr, + IndexVal)) + return; + + QualType Ty = getFunctionOrMethodParamType(D, IndexVal); + if (!Ty->isDependentType() && !Ty->isIntegralType(Context)) { + Diag(ParamExpr->getLocStart(), diag::err_attribute_integers_only) + << &TmpAttr << FuncDecl->getParamDecl(IndexVal)->getSourceRange(); + return; + } + + // We cannot use the Idx returned from checkFunctionOrMethodParameterIndex + // because that has corrected for the implicit this parameter, and is zero- + // based. The attribute expects what the user wrote explicitly. + llvm::APSInt Val; + ParamExpr->EvaluateAsInt(Val, Context); + + D->addAttr(::new (Context) AllocAlignAttr( + AttrRange, Context, Val.getZExtValue(), SpellingListIndex)); +} + /// Normalize the attribute, __foo__ becomes foo. /// Returns true if normalization was applied. static bool normalizeName(StringRef &AttrName) { @@ -1839,6 +1923,17 @@ static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &Attr) { Attr.getName())) return; + if (Attr.isDeclspecAttribute()) { + const auto &Triple = S.getASTContext().getTargetInfo().getTriple(); + const auto &Arch = Triple.getArch(); + if (Arch != llvm::Triple::x86 && + (Arch != llvm::Triple::arm && Arch != llvm::Triple::thumb)) { + S.Diag(Attr.getLoc(), diag::err_attribute_not_supported_on_arch) + << Attr.getName() << Triple.getArchName(); + return; + } + } + D->addAttr(::new (S.Context) NakedAttr(Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); } @@ -2409,6 +2504,32 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, } } +static void handleExternalSourceSymbolAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) + return; + assert(checkAttributeAtMostNumArgs(S, Attr, 3) && + "Invalid number of arguments in an external_source_symbol attribute"); + + if (!isa<NamedDecl>(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedNamedDecl; + return; + } + + StringRef Language; + if (const auto *SE = dyn_cast_or_null<StringLiteral>(Attr.getArgAsExpr(0))) + Language = SE->getString(); + StringRef DefinedIn; + if (const auto *SE = dyn_cast_or_null<StringLiteral>(Attr.getArgAsExpr(1))) + DefinedIn = SE->getString(); + bool IsGeneratedDeclaration = Attr.getArgAsIdent(2) != nullptr; + + D->addAttr(::new (S.Context) ExternalSourceSymbolAttr( + Attr.getRange(), S.Context, Language, DefinedIn, IsGeneratedDeclaration, + Attr.getAttributeSpellingListIndex())); +} + template <class T> static T *mergeVisibilityAttr(Sema &S, Decl *D, SourceRange range, typename T::VisibilityType value, @@ -2917,6 +3038,28 @@ static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) { Attr.getAttributeSpellingListIndex())); } +static void handleEnumExtensibilityAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + if (!Attr.isArgIdent(0)) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) + << Attr.getName() << 0 << AANT_ArgumentIdentifier; + return; + } + + EnumExtensibilityAttr::Kind ExtensibilityKind; + IdentifierInfo *II = Attr.getArgAsIdent(0)->Ident; + if (!EnumExtensibilityAttr::ConvertStrToKind(II->getName(), + ExtensibilityKind)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) + << Attr.getName() << II; + return; + } + + D->addAttr(::new (S.Context) EnumExtensibilityAttr( + Attr.getRange(), S.Context, ExtensibilityKind, + Attr.getAttributeSpellingListIndex())); +} + /// Handle __attribute__((format_arg((idx)))) attribute based on /// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html static void handleFormatArgAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -3193,8 +3336,9 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D, } if (!RD->isCompleteDefinition()) { - S.Diag(Attr.getLoc(), - diag::warn_transparent_union_attribute_not_definition); + if (!RD->isBeingDefined()) + S.Diag(Attr.getLoc(), + diag::warn_transparent_union_attribute_not_definition); return; } @@ -4048,6 +4192,26 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) { } } +static void handleSuppressAttr(Sema &S, Decl *D, const AttributeList &Attr) { + if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) + return; + + std::vector<StringRef> DiagnosticIdentifiers; + for (unsigned I = 0, E = Attr.getNumArgs(); I != E; ++I) { + StringRef RuleName; + + if (!S.checkStringLiteralArgumentAttr(Attr, I, RuleName, nullptr)) + return; + + // FIXME: Warn if the rule name is unknown. This is tricky because only + // clang-tidy knows about available rules. + DiagnosticIdentifiers.push_back(RuleName); + } + D->addAttr(::new (S.Context) SuppressAttr( + Attr.getRange(), S.Context, DiagnosticIdentifiers.data(), + DiagnosticIdentifiers.size(), Attr.getAttributeSpellingListIndex())); +} + bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, const FunctionDecl *FD) { if (attr.isInvalid()) @@ -4397,6 +4561,19 @@ static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D, Attr.getAttributeSpellingListIndex())); } +static void handleXRayLogArgsAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + uint64_t ArgCount; + if (!checkFunctionOrMethodParameterIndex(S, D, Attr, 1, Attr.getArgAsExpr(0), + ArgCount)) + return; + + // ArgCount isn't a parameter index [0;n), it's a count [1;n] - hence + 1. + D->addAttr(::new (S.Context) + XRayLogArgsAttr(Attr.getRange(), S.Context, ++ArgCount, + Attr.getAttributeSpellingListIndex())); +} + //===----------------------------------------------------------------------===// // Checker-specific attribute handlers. //===----------------------------------------------------------------------===// @@ -5126,6 +5303,32 @@ static void handleAnyX86InterruptAttr(Sema &S, Decl *D, D->addAttr(UsedAttr::CreateImplicit(S.Context)); } +static void handleAVRInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) { + if (!isFunctionOrMethod(D)) { + S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) + << "'interrupt'" << ExpectedFunction; + return; + } + + if (!checkAttributeNumArgs(S, Attr, 0)) + return; + + handleSimpleAttribute<AVRInterruptAttr>(S, D, Attr); +} + +static void handleAVRSignalAttr(Sema &S, Decl *D, const AttributeList &Attr) { + if (!isFunctionOrMethod(D)) { + S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) + << "'signal'" << ExpectedFunction; + return; + } + + if (!checkAttributeNumArgs(S, Attr, 0)) + return; + + handleSimpleAttribute<AVRSignalAttr>(S, D, Attr); +} + static void handleInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) { // Dispatch the interrupt attribute based on the current target. switch (S.Context.getTargetInfo().getTriple().getArch()) { @@ -5140,6 +5343,9 @@ static void handleInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) { case llvm::Triple::x86_64: handleAnyX86InterruptAttr(S, D, Attr); break; + case llvm::Triple::avr: + handleAVRInterruptAttr(S, D, Attr); + break; default: handleARMInterruptAttr(S, D, Attr); break; @@ -5700,6 +5906,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_AMDGPUNumVGPR: handleAMDGPUNumVGPRAttr(S, D, Attr); break; + case AttributeList::AT_AVRSignal: + handleAVRSignalAttr(S, D, Attr); + break; case AttributeList::AT_IBAction: handleSimpleAttribute<IBActionAttr>(S, D, Attr); break; @@ -5772,6 +5981,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_ExtVectorType: handleExtVectorTypeAttr(S, scope, D, Attr); break; + case AttributeList::AT_ExternalSourceSymbol: + handleExternalSourceSymbolAttr(S, D, Attr); + break; case AttributeList::AT_MinSize: handleMinSizeAttr(S, D, Attr); break; @@ -5781,6 +5993,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_FlagEnum: handleSimpleAttribute<FlagEnumAttr>(S, D, Attr); break; + case AttributeList::AT_EnumExtensibility: + handleEnumExtensibilityAttr(S, D, Attr); + break; case AttributeList::AT_Flatten: handleSimpleAttribute<FlattenAttr>(S, D, Attr); break; @@ -5837,6 +6052,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_AssumeAligned: handleAssumeAlignedAttr(S, D, Attr); break; + case AttributeList::AT_AllocAlign: + handleAllocAlignAttr(S, D, Attr); + break; case AttributeList::AT_Overloadable: handleSimpleAttribute<OverloadableAttr>(S, D, Attr); break; @@ -6056,6 +6274,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_PreserveAll: handleCallConvAttr(S, D, Attr); break; + case AttributeList::AT_Suppress: + handleSuppressAttr(S, D, Attr); + break; case AttributeList::AT_OpenCLKernel: handleSimpleAttribute<OpenCLKernelAttr>(S, D, Attr); break; @@ -6223,6 +6444,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_XRayInstrument: handleSimpleAttribute<XRayInstrumentAttr>(S, D, Attr); break; + case AttributeList::AT_XRayLogArgs: + handleXRayLogArgsAttr(S, D, Attr); + break; } } @@ -6282,6 +6506,15 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, } } +// Helper for delayed proccessing TransparentUnion attribute. +void Sema::ProcessDeclAttributeDelayed(Decl *D, const AttributeList *AttrList) { + for (const AttributeList *Attr = AttrList; Attr; Attr = Attr->getNext()) + if (Attr->getKind() == AttributeList::AT_TransparentUnion) { + handleTransparentUnionAttr(*this, D, *Attr); + break; + } +} + // Annotation attributes are the only attributes allowed after an access // specifier. bool Sema::ProcessAccessDeclAttributeList(AccessSpecDecl *ASDecl, @@ -6611,6 +6844,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, // Diagnostics for deprecated or unavailable. unsigned diag, diag_message, diag_fwdclass_message; unsigned diag_available_here = diag::note_availability_specified_here; + SourceLocation NoteLocation = D->getLocation(); // Matches 'diag::note_property_attribute' options. unsigned property_note_select; @@ -6633,6 +6867,8 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, diag_fwdclass_message = diag::warn_deprecated_fwdclass_message; property_note_select = /* deprecated */ 0; available_here_select_kind = /* deprecated */ 2; + if (const auto *attr = D->getAttr<DeprecatedAttr>()) + NoteLocation = attr->getLocation(); break; case AR_Unavailable: @@ -6751,7 +6987,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, } } else - S.Diag(D->getLocation(), diag_available_here) + S.Diag(NoteLocation, diag_available_here) << D << available_here_select_kind; if (K == AR_NotYetIntroduced) |