diff --git a/clang/include/clang/Sema/ParsedAttr.h b/clang/include/clang/Sema/ParsedAttr.h index 43c21faaece9fa..0d731d9150a8a3 100644 --- a/clang/include/clang/Sema/ParsedAttr.h +++ b/clang/include/clang/Sema/ParsedAttr.h @@ -573,6 +573,16 @@ class ParsedAttr final return MacroExpansionLoc; } + /// Check if the attribute has exactly as many args as Num. May output an + /// error. Returns false if a diagnostic is produced. + bool checkExactlyNumArgs(class Sema &S, unsigned Num) const; + /// Check if the attribute has at least as many args as Num. May output an + /// error. Returns false if a diagnostic is produced. + bool checkAtLeastNumArgs(class Sema &S, unsigned Num) const; + /// Check if the attribute has at most as many args as Num. May output an + /// error. Returns false if a diagnostic is produced. + bool checkAtMostNumArgs(class Sema &S, unsigned Num) const; + bool isTargetSpecificAttr() const; bool isTypeAttr() const; bool isStmtAttr() const; diff --git a/clang/lib/Sema/ParsedAttr.cpp b/clang/lib/Sema/ParsedAttr.cpp index 3ef8498baffdf8..c6a3d7c4342c9b 100644 --- a/clang/lib/Sema/ParsedAttr.cpp +++ b/clang/lib/Sema/ParsedAttr.cpp @@ -204,3 +204,35 @@ bool ParsedAttr::hasVariadicArg() const { // whether it's truly variadic or not. return getInfo().OptArgs == 15; } + +static unsigned getNumAttributeArgs(const ParsedAttr &AL) { + // FIXME: Include the type in the argument list. + return AL.getNumArgs() + AL.hasParsedType(); +} + +template +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 << Num; + return false; + } + return true; +} + +bool ParsedAttr::checkExactlyNumArgs(Sema &S, unsigned Num) const { + return checkAttributeNumArgsImpl(S, *this, Num, + diag::err_attribute_wrong_number_arguments, + std::not_equal_to()); +} +bool ParsedAttr::checkAtLeastNumArgs(Sema &S, unsigned Num) const { + return checkAttributeNumArgsImpl(S, *this, Num, + diag::err_attribute_too_few_arguments, + std::less()); +} +bool ParsedAttr::checkAtMostNumArgs(Sema &S, unsigned Num) const { + return checkAttributeNumArgsImpl(S, *this, Num, + diag::err_attribute_too_many_arguments, + std::greater()); +} diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 4376342185fb67..5b9acda6738ebc 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -191,44 +191,6 @@ static unsigned getNumAttributeArgs(const ParsedAttr &AL) { return AL.getNumArgs() + AL.hasParsedType(); } -template -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 << Num; - return false; - } - - return true; -} - -/// Check if the attribute has exactly as many args as Num. May -/// output an error. -static bool checkAttributeNumArgs(Sema &S, const ParsedAttr &AL, unsigned Num) { - return checkAttributeNumArgsImpl(S, AL, Num, - diag::err_attribute_wrong_number_arguments, - std::not_equal_to()); -} - -/// Check if the attribute has at least as many args as Num. May -/// output an error. -static bool checkAttributeAtLeastNumArgs(Sema &S, const ParsedAttr &AL, - unsigned Num) { - return checkAttributeNumArgsImpl(S, AL, Num, - diag::err_attribute_too_few_arguments, - std::less()); -} - -/// Check if the attribute has at most as many args as Num. May -/// output an error. -static bool checkAttributeAtMostNumArgs(Sema &S, const ParsedAttr &AL, - unsigned Num) { - return checkAttributeNumArgsImpl(S, AL, Num, - diag::err_attribute_too_many_arguments, - std::greater()); -} - /// A helper function to provide Attribute Location for the Attr types /// AND the ParsedAttr. template @@ -771,7 +733,7 @@ static void handlePtGuardedByAttr(Sema &S, Decl *D, const ParsedAttr &AL) { static bool checkAcquireOrderAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL, SmallVectorImpl &Args) { - if (!checkAttributeAtLeastNumArgs(S, AL, 1)) + if (!AL.checkAtLeastNumArgs(S, 1)) return false; // Check that this attribute only applies to lockable types. @@ -867,8 +829,7 @@ static bool checkParamIsIntegerType(Sema &S, const FunctionDecl *FD, } static void handleAllocSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (!checkAttributeAtLeastNumArgs(S, AL, 1) || - !checkAttributeAtMostNumArgs(S, AL, 2)) + if (!AL.checkAtLeastNumArgs(S, 1) || !AL.checkAtMostNumArgs(S, 2)) return; const auto *FD = cast(D); @@ -904,7 +865,7 @@ static void handleAllocSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { static bool checkTryLockFunAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL, SmallVectorImpl &Args) { - if (!checkAttributeAtLeastNumArgs(S, AL, 1)) + if (!AL.checkAtLeastNumArgs(S, 1)) return false; if (!isIntOrBool(AL.getArgAsExpr(0))) { @@ -951,7 +912,7 @@ static void handleLockReturnedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } static void handleLocksExcludedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (!checkAttributeAtLeastNumArgs(S, AL, 1)) + if (!AL.checkAtLeastNumArgs(S, 1)) return; // check that all arguments are lockable objects @@ -1193,7 +1154,7 @@ static bool checkForConsumableClass(Sema &S, const CXXMethodDecl *MD, } static void handleCallableWhenAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (!checkAttributeAtLeastNumArgs(S, AL, 1)) + if (!AL.checkAtLeastNumArgs(S, 1)) return; if (!checkForConsumableClass(S, cast(D), AL)) @@ -2016,7 +1977,7 @@ static void handleCPUSpecificAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } } - if (!checkAttributeAtLeastNumArgs(S, AL, 1)) + if (!AL.checkAtLeastNumArgs(S, 1)) return; SmallVector CPUs; @@ -2120,7 +2081,7 @@ static void handleNoCfCheckAttr(Sema &S, Decl *D, const ParsedAttr &Attrs) { } bool Sema::CheckAttrNoArgs(const ParsedAttr &Attrs) { - if (!checkAttributeNumArgs(*this, Attrs, 0)) { + if (!Attrs.checkExactlyNumArgs(*this, 0)) { Attrs.setInvalid(); return true; } @@ -2492,7 +2453,7 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr( } static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (!checkAttributeNumArgs(S, AL, 1)) + if (!AL.checkExactlyNumArgs(S, 1)) return; IdentifierLoc *Platform = AL.getArgAsIdent(0); @@ -2600,10 +2561,8 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { static void handleExternalSourceSymbolAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (!checkAttributeAtLeastNumArgs(S, AL, 1)) + if (!AL.checkAtLeastNumArgs(S, 1) || !AL.checkAtMostNumArgs(S, 3)) return; - assert(checkAttributeAtMostNumArgs(S, AL, 3) && - "Invalid number of arguments in an external_source_symbol attribute"); StringRef Language; if (const auto *SE = dyn_cast_or_null(AL.getArgAsExpr(0))) @@ -4690,7 +4649,7 @@ static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } static void handleSuppressAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (!checkAttributeAtLeastNumArgs(S, AL, 1)) + if (!AL.checkAtLeastNumArgs(S, 1)) return; std::vector DiagnosticIdentifiers; @@ -4780,7 +4739,7 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC, } unsigned ReqArgs = Attrs.getKind() == ParsedAttr::AT_Pcs ? 1 : 0; - if (!checkAttributeNumArgs(*this, Attrs, ReqArgs)) { + if (!Attrs.checkExactlyNumArgs(*this, ReqArgs)) { Attrs.setInvalid(); return true; } @@ -5008,7 +4967,7 @@ bool Sema::CheckRegparmAttr(const ParsedAttr &AL, unsigned &numParams) { if (AL.isInvalid()) return true; - if (!checkAttributeNumArgs(*this, AL, 1)) { + if (!AL.checkExactlyNumArgs(*this, 1)) { AL.setInvalid(); return true; } @@ -5097,8 +5056,7 @@ void Sema::AddLaunchBoundsAttr(Decl *D, const AttributeCommonInfo &CI, } static void handleLaunchBoundsAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (!checkAttributeAtLeastNumArgs(S, AL, 1) || - !checkAttributeAtMostNumArgs(S, AL, 2)) + if (!AL.checkAtLeastNumArgs(S, 1) || !AL.checkAtMostNumArgs(S, 2)) return; S.AddLaunchBoundsAttr(D, AL, AL.getArgAsExpr(0), @@ -5145,7 +5103,7 @@ static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D, return; } - if (!checkAttributeNumArgs(S, AL, 1)) + if (!AL.checkExactlyNumArgs(S, 1)) return; if (!isa(D)) { @@ -5952,7 +5910,7 @@ static void handleSwiftAsyncError(Sema &S, Decl *D, const ParsedAttr &AL) { switch (ConvKind) { case SwiftAsyncErrorAttr::ZeroArgument: case SwiftAsyncErrorAttr::NonZeroArgument: { - if (!checkAttributeNumArgs(S, AL, 2)) + if (!AL.checkExactlyNumArgs(S, 2)) return; Expr *IdxExpr = AL.getArgAsExpr(1); @@ -5962,7 +5920,7 @@ static void handleSwiftAsyncError(Sema &S, Decl *D, const ParsedAttr &AL) { } case SwiftAsyncErrorAttr::NonNullError: case SwiftAsyncErrorAttr::None: { - if (!checkAttributeNumArgs(S, AL, 1)) + if (!AL.checkExactlyNumArgs(S, 1)) return; break; } @@ -6288,7 +6246,7 @@ static void handleSwiftAsyncName(Sema &S, Decl *D, const ParsedAttr &AL) { static void handleSwiftNewType(Sema &S, Decl *D, const ParsedAttr &AL) { // Make sure that there is an identifier as the annotation's single argument. - if (!checkAttributeNumArgs(S, AL, 1)) + if (!AL.checkExactlyNumArgs(S, 1)) return; if (!AL.isArgIdent(0)) { @@ -6330,11 +6288,11 @@ static void handleSwiftAsyncAttr(Sema &S, Decl *D, const ParsedAttr &AL) { ParamIdx Idx; if (Kind == SwiftAsyncAttr::None) { // If this is 'none', then there shouldn't be any additional arguments. - if (!checkAttributeNumArgs(S, AL, 1)) + if (!AL.checkExactlyNumArgs(S, 1)) return; } else { // Non-none swift_async requires a completion handler index argument. - if (!checkAttributeNumArgs(S, AL, 2)) + if (!AL.checkExactlyNumArgs(S, 2)) return; Expr *HandlerIdx = AL.getArgAsExpr(1); @@ -6498,7 +6456,7 @@ static void handleAbiTagAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } if (AL.getNumArgs() == 0) Tags.push_back(NS->getName()); - } else if (!checkAttributeAtLeastNumArgs(S, AL, 1)) + } else if (!AL.checkAtLeastNumArgs(S, 1)) return; // Store tags sorted and without duplicates. @@ -6556,7 +6514,7 @@ static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } // The attribute takes one integer argument. - if (!checkAttributeNumArgs(S, AL, 1)) + if (!AL.checkExactlyNumArgs(S, 1)) return; if (!AL.isArgExpr(0)) { @@ -6642,7 +6600,7 @@ static void handleMipsInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } static void handleM68kInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (!checkAttributeNumArgs(S, AL, 1)) + if (!AL.checkExactlyNumArgs(S, 1)) return; if (!AL.isArgExpr(0)) { @@ -6745,7 +6703,7 @@ static void handleAVRInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - if (!checkAttributeNumArgs(S, AL, 0)) + if (!AL.checkExactlyNumArgs(S, 0)) return; handleSimpleAttribute(S, D, AL); @@ -6758,7 +6716,7 @@ static void handleAVRSignalAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - if (!checkAttributeNumArgs(S, AL, 0)) + if (!AL.checkExactlyNumArgs(S, 0)) return; handleSimpleAttribute(S, D, AL); @@ -6889,7 +6847,7 @@ static void handleRISCVInterruptAttr(Sema &S, Decl *D, } // Check the attribute argument. Argument is optional. - if (!checkAttributeAtMostNumArgs(S, AL, 1)) + if (!AL.checkAtMostNumArgs(S, 1)) return; StringRef Str; @@ -7062,8 +7020,7 @@ void Sema::addAMDGPUWavesPerEUAttr(Decl *D, const AttributeCommonInfo &CI, } static void handleAMDGPUWavesPerEUAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (!checkAttributeAtLeastNumArgs(S, AL, 1) || - !checkAttributeAtMostNumArgs(S, AL, 2)) + if (!AL.checkAtLeastNumArgs(S, 1) || !AL.checkAtMostNumArgs(S, 2)) return; Expr *MinExpr = AL.getArgAsExpr(0); @@ -7286,7 +7243,7 @@ static void handleReleaseCapabilityAttr(Sema &S, Decl *D, static void handleRequiresCapabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (!checkAttributeAtLeastNumArgs(S, AL, 1)) + if (!AL.checkAtLeastNumArgs(S, 1)) return; // check that all arguments are lockable objects @@ -7320,7 +7277,7 @@ static void handleDeprecatedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Only support a single optional message for Declspec and CXX11. if (AL.isDeclspecAttribute() || AL.isCXX11Attribute()) - checkAttributeAtMostNumArgs(S, AL, 1); + AL.checkAtMostNumArgs(S, 1); else if (AL.isArgExpr(1) && AL.getArgAsExpr(1) && !S.checkStringLiteralArgumentAttr(AL, 1, Replacement)) return; @@ -7338,7 +7295,7 @@ static bool isGlobalVar(const Decl *D) { } static void handleNoSanitizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (!checkAttributeAtLeastNumArgs(S, AL, 1)) + if (!AL.checkAtLeastNumArgs(S, 1)) return; std::vector Sanitizers; @@ -7433,15 +7390,14 @@ static bool handleCommonAttributeFeatures(Sema &S, Decl *D, if (AL.getMinArgs() == AL.getMaxArgs()) { // If there are no optional arguments, then checking for the argument count // is trivial. - if (!checkAttributeNumArgs(S, AL, AL.getMinArgs())) + if (!AL.checkExactlyNumArgs(S, AL.getMinArgs())) return true; } else { // There are optional arguments, so checking is slightly more involved. - if (AL.getMinArgs() && - !checkAttributeAtLeastNumArgs(S, AL, AL.getMinArgs())) + if (AL.getMinArgs() && !AL.checkAtLeastNumArgs(S, AL.getMinArgs())) return true; else if (!AL.hasVariadicArg() && AL.getMaxArgs() && - !checkAttributeAtMostNumArgs(S, AL, AL.getMaxArgs())) + !AL.checkAtMostNumArgs(S, AL.getMaxArgs())) return true; }