diff options
Diffstat (limited to 'clang/lib/Sema/SemaDeclAttr.cpp')
-rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 454 |
1 files changed, 354 insertions, 100 deletions
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 838fd48357fb..a303c7f57280 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -24,6 +24,7 @@ #include "clang/AST/Type.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/DarwinSDKInfo.h" +#include "clang/Basic/HLSLRuntime.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" @@ -38,7 +39,6 @@ #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" -#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/IR/Assumptions.h" @@ -46,6 +46,7 @@ #include "llvm/Support/Error.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" +#include <optional> using namespace clang; using namespace sema; @@ -201,7 +202,7 @@ static unsigned getNumAttributeArgs(const ParsedAttr &AL) { /// A helper function to provide Attribute Location for the Attr types /// AND the ParsedAttr. template <typename AttrInfo> -static std::enable_if_t<std::is_base_of<Attr, AttrInfo>::value, SourceLocation> +static std::enable_if_t<std::is_base_of_v<Attr, AttrInfo>, SourceLocation> getAttrLoc(const AttrInfo &AL) { return AL.getLocation(); } @@ -216,7 +217,7 @@ template <typename AttrInfo> static bool checkUInt32Argument(Sema &S, const AttrInfo &AI, const Expr *Expr, uint32_t &Val, unsigned Idx = UINT_MAX, bool StrictlyUnsigned = false) { - Optional<llvm::APSInt> I = llvm::APSInt(32); + std::optional<llvm::APSInt> I = llvm::APSInt(32); if (Expr->isTypeDependent() || !(I = Expr->getIntegerConstantExpr(S.Context))) { if (Idx != UINT_MAX) @@ -308,7 +309,7 @@ static bool checkFunctionOrMethodParameterIndex( unsigned NumParams = (HP ? getFunctionOrMethodNumParams(D) : 0) + HasImplicitThisParam; - Optional<llvm::APSInt> IdxInt; + std::optional<llvm::APSInt> IdxInt; if (IdxExpr->isTypeDependent() || !(IdxInt = IdxExpr->getIntegerConstantExpr(S.Context))) { S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type) @@ -1689,7 +1690,7 @@ void Sema::AddAssumeAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E, } if (!E->isValueDependent()) { - Optional<llvm::APSInt> I = llvm::APSInt(64); + std::optional<llvm::APSInt> I = llvm::APSInt(64); if (!(I = E->getIntegerConstantExpr(Context))) { if (OE) Diag(AttrLoc, diag::err_attribute_argument_n_type) @@ -1876,8 +1877,7 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) { for (const auto *I : D->specific_attrs<OwnershipAttr>()) { // Cannot have two ownership attributes of different kinds for the same // index. - if (I->getOwnKind() != K && I->args_end() != - std::find(I->args_begin(), I->args_end(), Idx)) { + if (I->getOwnKind() != K && llvm::is_contained(I->args(), Idx)) { S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << I; return; } else if (K == OwnershipAttr::Returns && @@ -2329,6 +2329,10 @@ static void handleUnusedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { static void handleConstructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) { uint32_t priority = ConstructorAttr::DefaultPriority; + if (S.getLangOpts().HLSL && AL.getNumArgs()) { + S.Diag(AL.getLoc(), diag::err_hlsl_init_priority_unsupported); + return; + } if (AL.getNumArgs() && !checkUInt32Argument(S, AL, AL.getArgAsExpr(0), priority)) return; @@ -2630,7 +2634,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } if (II->isStr("fuchsia")) { - Optional<unsigned> Min, Sub; + std::optional<unsigned> Min, Sub; if ((Min = Introduced.Version.getMinor()) || (Sub = Introduced.Version.getSubminor())) { S.Diag(AL.getLoc(), diag::warn_availability_fuchsia_unavailable_minor); @@ -2672,8 +2676,8 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (IOSToWatchOSMapping) { if (auto MappedVersion = IOSToWatchOSMapping->map( - Version, MinimumWatchOSVersion, None)) { - return MappedVersion.value(); + Version, MinimumWatchOSVersion, std::nullopt)) { + return *MappedVersion; } } @@ -2682,10 +2686,10 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (NewMajor >= 2) { if (Version.getMinor()) { if (Version.getSubminor()) - return VersionTuple(NewMajor, Version.getMinor().value(), - Version.getSubminor().value()); + return VersionTuple(NewMajor, *Version.getMinor(), + *Version.getSubminor()); else - return VersionTuple(NewMajor, Version.getMinor().value()); + return VersionTuple(NewMajor, *Version.getMinor()); } return VersionTuple(NewMajor); } @@ -2727,8 +2731,8 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return Version; if (IOSToTvOSMapping) { - if (auto MappedVersion = - IOSToTvOSMapping->map(Version, VersionTuple(0, 0), None)) { + if (auto MappedVersion = IOSToTvOSMapping->map( + Version, VersionTuple(0, 0), std::nullopt)) { return *MappedVersion; } } @@ -2791,24 +2795,25 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // attributes that are inferred from 'ios'. NewII = &S.Context.Idents.get("maccatalyst"); auto RemapMacOSVersion = - [&](const VersionTuple &V) -> Optional<VersionTuple> { + [&](const VersionTuple &V) -> std::optional<VersionTuple> { if (V.empty()) - return None; + return std::nullopt; // API_TO_BE_DEPRECATED is 100000. if (V.getMajor() == 100000) return VersionTuple(100000); // The minimum iosmac version is 13.1 - return MacOStoMacCatalystMapping->map(V, VersionTuple(13, 1), None); + return MacOStoMacCatalystMapping->map(V, VersionTuple(13, 1), + std::nullopt); }; - Optional<VersionTuple> NewIntroduced = - RemapMacOSVersion(Introduced.Version), - NewDeprecated = - RemapMacOSVersion(Deprecated.Version), - NewObsoleted = - RemapMacOSVersion(Obsoleted.Version); + std::optional<VersionTuple> NewIntroduced = + RemapMacOSVersion(Introduced.Version), + NewDeprecated = + RemapMacOSVersion(Deprecated.Version), + NewObsoleted = + RemapMacOSVersion(Obsoleted.Version); if (NewIntroduced || NewDeprecated || NewObsoleted) { auto VersionOrEmptyVersion = - [](const Optional<VersionTuple> &V) -> VersionTuple { + [](const std::optional<VersionTuple> &V) -> VersionTuple { return V ? *V : VersionTuple(); }; AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr( @@ -3032,7 +3037,7 @@ static void handleSentinelAttr(Sema &S, Decl *D, const ParsedAttr &AL) { unsigned sentinel = (unsigned)SentinelAttr::DefaultSentinel; if (AL.getNumArgs() > 0) { Expr *E = AL.getArgAsExpr(0); - Optional<llvm::APSInt> Idx = llvm::APSInt(32); + std::optional<llvm::APSInt> Idx = llvm::APSInt(32); if (E->isTypeDependent() || !(Idx = E->getIntegerConstantExpr(S.Context))) { S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) << AL << 1 << AANT_ArgumentIntegerConstant << E->getSourceRange(); @@ -3051,7 +3056,7 @@ static void handleSentinelAttr(Sema &S, Decl *D, const ParsedAttr &AL) { unsigned nullPos = (unsigned)SentinelAttr::DefaultNullPos; if (AL.getNumArgs() > 1) { Expr *E = AL.getArgAsExpr(1); - Optional<llvm::APSInt> Idx = llvm::APSInt(32); + std::optional<llvm::APSInt> Idx = llvm::APSInt(32); if (E->isTypeDependent() || !(Idx = E->getIntegerConstantExpr(S.Context))) { S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) << AL << 2 << AANT_ArgumentIntegerConstant << E->getSourceRange(); @@ -3146,7 +3151,7 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const ParsedAttr &AL) { if (LO.CPlusPlus && !LO.CPlusPlus20) S.Diag(AL.getLoc(), diag::ext_cxx20_attr) << AL; - // Since this this is spelled [[nodiscard]], get the optional string + // Since this is spelled [[nodiscard]], get the optional string // literal. If in C++ mode, but not in C++2a mode, diagnose as an // extension. // FIXME: C2x should support this feature as well, even as an extension. @@ -3391,7 +3396,7 @@ static void handleCodeSegAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // handled later in the process, once we know how many exist. bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) { enum FirstParam { Unsupported, Duplicate, Unknown }; - enum SecondParam { None, Architecture, Tune }; + enum SecondParam { None, CPU, Tune }; enum ThirdParam { Target, TargetClones }; if (AttrStr.contains("fpmath=")) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) @@ -3403,24 +3408,22 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) { return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) << Unsupported << None << "tune=" << Target; - ParsedTargetAttr ParsedAttrs = TargetAttr::parse(AttrStr); + ParsedTargetAttr ParsedAttrs = + Context.getTargetInfo().parseTargetAttr(AttrStr); - if (!ParsedAttrs.Architecture.empty() && - !Context.getTargetInfo().isValidCPUName(ParsedAttrs.Architecture)) + if (!ParsedAttrs.CPU.empty() && + !Context.getTargetInfo().isValidCPUName(ParsedAttrs.CPU)) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) - << Unknown << Architecture << ParsedAttrs.Architecture << Target; + << Unknown << CPU << ParsedAttrs.CPU << Target; if (!ParsedAttrs.Tune.empty() && !Context.getTargetInfo().isValidCPUName(ParsedAttrs.Tune)) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) << Unknown << Tune << ParsedAttrs.Tune << Target; - if (ParsedAttrs.DuplicateArchitecture) - return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) - << Duplicate << None << "arch=" << Target; - if (ParsedAttrs.DuplicateTune) + if (ParsedAttrs.Duplicate != "") return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) - << Duplicate << None << "tune=" << Target; + << Duplicate << None << ParsedAttrs.Duplicate << Target; for (const auto &Feature : ParsedAttrs.Features) { auto CurFeature = StringRef(Feature).drop_front(); // remove + or -. @@ -3434,8 +3437,7 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) { if (ParsedAttrs.BranchProtection.empty()) return false; if (!Context.getTargetInfo().validateBranchProtection( - ParsedAttrs.BranchProtection, ParsedAttrs.Architecture, BPI, - DiagMsg)) { + ParsedAttrs.BranchProtection, ParsedAttrs.CPU, BPI, DiagMsg)) { if (DiagMsg.empty()) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) << Unsupported << None << "branch-protection" << Target; @@ -3448,6 +3450,42 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) { return false; } +// Check Target Version attrs +bool Sema::checkTargetVersionAttr(SourceLocation LiteralLoc, StringRef &AttrStr, + bool &isDefault) { + enum FirstParam { Unsupported }; + enum SecondParam { None }; + enum ThirdParam { Target, TargetClones, TargetVersion }; + if (AttrStr.trim() == "default") + isDefault = true; + llvm::SmallVector<StringRef, 8> Features; + AttrStr.split(Features, "+"); + for (auto &CurFeature : Features) { + CurFeature = CurFeature.trim(); + if (CurFeature == "default") + continue; + if (!Context.getTargetInfo().validateCpuSupports(CurFeature)) + return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) + << Unsupported << None << CurFeature << TargetVersion; + } + return false; +} + +static void handleTargetVersionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + StringRef Str; + SourceLocation LiteralLoc; + bool isDefault = false; + if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc) || + S.checkTargetVersionAttr(LiteralLoc, Str, isDefault)) + return; + // Do not create default only target_version attribute + if (!isDefault) { + TargetVersionAttr *NewAttr = + ::new (S.Context) TargetVersionAttr(S.Context, AL, Str); + D->addAttr(NewAttr); + } +} + static void handleTargetAttr(Sema &S, Decl *D, const ParsedAttr &AL) { StringRef Str; SourceLocation LiteralLoc; @@ -3459,12 +3497,12 @@ static void handleTargetAttr(Sema &S, Decl *D, const ParsedAttr &AL) { D->addAttr(NewAttr); } -bool Sema::checkTargetClonesAttrString(SourceLocation LiteralLoc, StringRef Str, - const StringLiteral *Literal, - bool &HasDefault, bool &HasCommas, - SmallVectorImpl<StringRef> &Strings) { +bool Sema::checkTargetClonesAttrString( + SourceLocation LiteralLoc, StringRef Str, const StringLiteral *Literal, + bool &HasDefault, bool &HasCommas, bool &HasNotDefault, + SmallVectorImpl<SmallString<64>> &StringsBuffer) { enum FirstParam { Unsupported, Duplicate, Unknown }; - enum SecondParam { None, Architecture, Tune }; + enum SecondParam { None, CPU, Tune }; enum ThirdParam { Target, TargetClones }; HasCommas = HasCommas || Str.contains(','); // Warn on empty at the beginning of a string. @@ -3481,29 +3519,75 @@ bool Sema::checkTargetClonesAttrString(SourceLocation LiteralLoc, StringRef Str, getLangOpts(), Context.getTargetInfo()); bool DefaultIsDupe = false; + bool HasCodeGenImpact = false; if (Cur.empty()) return Diag(CurLoc, diag::warn_unsupported_target_attribute) << Unsupported << None << "" << TargetClones; - if (Cur.startswith("arch=")) { - if (!Context.getTargetInfo().isValidCPUName( - Cur.drop_front(sizeof("arch=") - 1))) + if (Context.getTargetInfo().getTriple().isAArch64()) { + // AArch64 target clones specific + if (Cur == "default") { + DefaultIsDupe = HasDefault; + HasDefault = true; + if (llvm::is_contained(StringsBuffer, Cur) || DefaultIsDupe) + Diag(CurLoc, diag::warn_target_clone_duplicate_options); + else + StringsBuffer.push_back(Cur); + } else { + std::pair<StringRef, StringRef> CurParts = {{}, Cur}; + llvm::SmallVector<StringRef, 8> CurFeatures; + while (!CurParts.second.empty()) { + CurParts = CurParts.second.split('+'); + StringRef CurFeature = CurParts.first.trim(); + if (!Context.getTargetInfo().validateCpuSupports(CurFeature)) { + Diag(CurLoc, diag::warn_unsupported_target_attribute) + << Unsupported << None << CurFeature << TargetClones; + continue; + } + std::string Options; + if (Context.getTargetInfo().getFeatureDepOptions(CurFeature, Options)) + HasCodeGenImpact = true; + CurFeatures.push_back(CurFeature); + } + // Canonize TargetClones Attributes + llvm::sort(CurFeatures); + SmallString<64> Res; + for (auto &CurFeat : CurFeatures) { + if (!Res.equals("")) + Res.append("+"); + Res.append(CurFeat); + } + if (llvm::is_contained(StringsBuffer, Res) || DefaultIsDupe) + Diag(CurLoc, diag::warn_target_clone_duplicate_options); + else if (!HasCodeGenImpact) + // Ignore features in target_clone attribute that don't impact + // code generation + Diag(CurLoc, diag::warn_target_clone_no_impact_options); + else if (!Res.empty()) { + StringsBuffer.push_back(Res); + HasNotDefault = true; + } + } + } else { + // Other targets ( currently X86 ) + if (Cur.startswith("arch=")) { + if (!Context.getTargetInfo().isValidCPUName( + Cur.drop_front(sizeof("arch=") - 1))) + return Diag(CurLoc, diag::warn_unsupported_target_attribute) + << Unsupported << CPU << Cur.drop_front(sizeof("arch=") - 1) + << TargetClones; + } else if (Cur == "default") { + DefaultIsDupe = HasDefault; + HasDefault = true; + } else if (!Context.getTargetInfo().isValidFeatureName(Cur)) return Diag(CurLoc, diag::warn_unsupported_target_attribute) - << Unsupported << Architecture - << Cur.drop_front(sizeof("arch=") - 1) << TargetClones; - } else if (Cur == "default") { - DefaultIsDupe = HasDefault; - HasDefault = true; - } else if (!Context.getTargetInfo().isValidFeatureName(Cur)) - return Diag(CurLoc, diag::warn_unsupported_target_attribute) - << Unsupported << None << Cur << TargetClones; - - if (llvm::is_contained(Strings, Cur) || DefaultIsDupe) - Diag(CurLoc, diag::warn_target_clone_duplicate_options); - // Note: Add even if there are duplicates, since it changes name mangling. - Strings.push_back(Cur); + << Unsupported << None << Cur << TargetClones; + if (llvm::is_contained(StringsBuffer, Cur) || DefaultIsDupe) + Diag(CurLoc, diag::warn_target_clone_duplicate_options); + // Note: Add even if there are duplicates, since it changes name mangling. + StringsBuffer.push_back(Cur); + } } - if (Str.rtrim().endswith(",")) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) << Unsupported << None << "" << TargetClones; @@ -3511,6 +3595,10 @@ bool Sema::checkTargetClonesAttrString(SourceLocation LiteralLoc, StringRef Str, } static void handleTargetClonesAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (S.Context.getTargetInfo().getTriple().isAArch64() && + !S.Context.getTargetInfo().hasFeature("fmv")) + return; + // Ensure we don't combine these with themselves, since that causes some // confusing behavior. if (const auto *Other = D->getAttr<TargetClonesAttr>()) { @@ -3522,7 +3610,8 @@ static void handleTargetClonesAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; SmallVector<StringRef, 2> Strings; - bool HasCommas = false, HasDefault = false; + SmallVector<SmallString<64>, 2> StringsBuffer; + bool HasCommas = false, HasDefault = false, HasNotDefault = false; for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) { StringRef CurStr; @@ -3531,13 +3620,21 @@ static void handleTargetClonesAttr(Sema &S, Decl *D, const ParsedAttr &AL) { S.checkTargetClonesAttrString( LiteralLoc, CurStr, cast<StringLiteral>(AL.getArgAsExpr(I)->IgnoreParenCasts()), - HasDefault, HasCommas, Strings)) + HasDefault, HasCommas, HasNotDefault, StringsBuffer)) return; } + for (auto &SmallStr : StringsBuffer) + Strings.push_back(SmallStr.str()); if (HasCommas && AL.getNumArgs() > 1) S.Diag(AL.getLoc(), diag::warn_target_clone_mixed_values); + if (S.Context.getTargetInfo().getTriple().isAArch64() && !HasDefault) { + // Add default attribute if there is no one + HasDefault = true; + Strings.push_back("default"); + } + if (!HasDefault) { S.Diag(AL.getLoc(), diag::err_target_clone_must_have_default); return; @@ -3554,6 +3651,10 @@ static void handleTargetClonesAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } } + // No multiversion if we have default version only. + if (S.Context.getTargetInfo().getTriple().isAArch64() && !HasNotDefault) + return; + cast<FunctionDecl>(D)->setIsMultiVersion(); TargetClonesAttr *NewAttr = ::new (S.Context) TargetClonesAttr(S.Context, AL, Strings.data(), Strings.size()); @@ -3730,6 +3831,11 @@ static void handleInitPriorityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { S.Diag(AL.getLoc(), diag::warn_attribute_ignored) << AL; return; } + + if (S.getLangOpts().HLSL) { + S.Diag(AL.getLoc(), diag::err_hlsl_init_priority_unsupported); + return; + } if (S.getCurFunctionOrMethodDecl()) { S.Diag(AL.getLoc(), diag::err_init_priority_object_attr); @@ -3884,27 +3990,38 @@ static void handleFormatAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!checkUInt32Argument(S, AL, FirstArgExpr, FirstArg, 3)) return; - // check if the function is variadic if the 3rd argument non-zero + // FirstArg == 0 is is always valid. if (FirstArg != 0) { - if (isFunctionOrMethodVariadic(D)) - ++NumArgs; // +1 for ... - else - S.Diag(D->getLocation(), diag::warn_gcc_requires_variadic_function) << AL; - } - - // strftime requires FirstArg to be 0 because it doesn't read from any - // variable the input is just the current time + the format string. - if (Kind == StrftimeFormat) { - if (FirstArg != 0) { + if (Kind == StrftimeFormat) { + // If the kind is strftime, FirstArg must be 0 because strftime does not + // use any variadic arguments. S.Diag(AL.getLoc(), diag::err_format_strftime_third_parameter) - << FirstArgExpr->getSourceRange(); - return; + << FirstArgExpr->getSourceRange() + << FixItHint::CreateReplacement(FirstArgExpr->getSourceRange(), "0"); + return; + } else if (isFunctionOrMethodVariadic(D)) { + // Else, if the function is variadic, then FirstArg must be 0 or the + // "position" of the ... parameter. It's unusual to use 0 with variadic + // functions, so the fixit proposes the latter. + if (FirstArg != NumArgs + 1) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) + << AL << 3 << FirstArgExpr->getSourceRange() + << FixItHint::CreateReplacement(FirstArgExpr->getSourceRange(), + std::to_string(NumArgs + 1)); + return; + } + } else { + // Inescapable GCC compatibility diagnostic. + S.Diag(D->getLocation(), diag::warn_gcc_requires_variadic_function) << AL; + if (FirstArg <= Idx) { + // Else, the function is not variadic, and FirstArg must be 0 or any + // parameter after the format parameter. We don't offer a fixit because + // there are too many possible good values. + S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) + << AL << 3 << FirstArgExpr->getSourceRange(); + return; + } } - // 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 << 3 << FirstArgExpr->getSourceRange(); - return; } FormatAttr *NewAttr = S.mergeFormatAttr(D, AL, II, Idx, FirstArg); @@ -4335,7 +4452,7 @@ void Sema::AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E, } const auto *VD = dyn_cast<VarDecl>(D); - if (VD && Context.getTargetInfo().isTLSSupported()) { + if (VD) { unsigned MaxTLSAlign = Context.toCharUnitsFromBits(Context.getTargetInfo().getMaxTLSAlign()) .getQuantity(); @@ -4500,7 +4617,7 @@ static void parseModeAttrArg(Sema &S, StringRef Str, unsigned &DestWidth, break; case 7: if (Str == "pointer") - DestWidth = S.Context.getTargetInfo().getPointerWidth(0); + DestWidth = S.Context.getTargetInfo().getPointerWidth(LangAS::Default); break; case 11: if (Str == "unwind_word") @@ -5388,7 +5505,7 @@ static Expr *makeLaunchBoundsArgExpr(Sema &S, Expr *E, if (E->isValueDependent()) return E; - Optional<llvm::APSInt> I = llvm::APSInt(64); + std::optional<llvm::APSInt> I = llvm::APSInt(64); if (!(I = E->getIntegerConstantExpr(S.Context))) { S.Diag(E->getExprLoc(), diag::err_attribute_argument_n_type) << &AL << Idx << AANT_ArgumentIntegerConstant << E->getSourceRange(); @@ -5543,9 +5660,10 @@ static bool ArmBuiltinAliasValid(unsigned BuiltinID, StringRef AliasName, const char *IntrinNames) { if (AliasName.startswith("__arm_")) AliasName = AliasName.substr(6); - const IntrinToName *It = std::lower_bound( - Map.begin(), Map.end(), BuiltinID, - [](const IntrinToName &L, unsigned Id) { return L.Id < Id; }); + const IntrinToName *It = + llvm::lower_bound(Map, BuiltinID, [](const IntrinToName &L, unsigned Id) { + return L.Id < Id; + }); if (It == Map.end() || It->Id != BuiltinID) return false; StringRef FullName(&IntrinNames[It->FullName]); @@ -6433,9 +6551,9 @@ validateSwiftFunctionName(Sema &S, const ParsedAttr &AL, SourceLocation Loc, } StringRef CurrentParam; - llvm::Optional<unsigned> SelfLocation; + std::optional<unsigned> SelfLocation; unsigned NewValueCount = 0; - llvm::Optional<unsigned> NewValueLocation; + std::optional<unsigned> NewValueLocation; do { std::tie(CurrentParam, Parameters) = Parameters.split(':'); @@ -6813,12 +6931,12 @@ static void handleUuidAttr(Sema &S, Decl *D, const ParsedAttr &AL) { static void handleHLSLNumThreadsAttr(Sema &S, Decl *D, const ParsedAttr &AL) { using llvm::Triple; Triple Target = S.Context.getTargetInfo().getTriple(); + auto Env = S.Context.getTargetInfo().getTriple().getEnvironment(); if (!llvm::is_contained({Triple::Compute, Triple::Mesh, Triple::Amplification, Triple::Library}, - Target.getEnvironment())) { + Env)) { uint32_t Pipeline = - (uint32_t)S.Context.getTargetInfo().getTriple().getEnvironment() - - (uint32_t)llvm::Triple::Pixel; + static_cast<uint32_t>(hlsl::getStageFromEnvironment(Env)); S.Diag(AL.getLoc(), diag::err_hlsl_attr_unsupported_in_stage) << AL << Pipeline << "Compute, Amplification, Mesh or Library"; return; @@ -6885,8 +7003,35 @@ HLSLNumThreadsAttr *Sema::mergeHLSLNumThreadsAttr(Decl *D, static void handleHLSLSVGroupIndexAttr(Sema &S, Decl *D, const ParsedAttr &AL) { using llvm::Triple; + auto Env = S.Context.getTargetInfo().getTriple().getEnvironment(); + if (Env != Triple::Compute && Env != Triple::Library) { + // FIXME: it is OK for a compute shader entry and pixel shader entry live in + // same HLSL file. Issue https://github.com/llvm/llvm-project/issues/57880. + ShaderStage Pipeline = hlsl::getStageFromEnvironment(Env); + S.Diag(AL.getLoc(), diag::err_hlsl_attr_unsupported_in_stage) + << AL << (uint32_t)Pipeline << "Compute"; + return; + } + + D->addAttr(::new (S.Context) HLSLSV_GroupIndexAttr(S.Context, AL)); +} + +static bool isLegalTypeForHLSLSV_DispatchThreadID(QualType T) { + if (!T->hasUnsignedIntegerRepresentation()) + return false; + if (const auto *VT = T->getAs<VectorType>()) + return VT->getNumElements() <= 3; + return true; +} + +static void handleHLSLSV_DispatchThreadIDAttr(Sema &S, Decl *D, + const ParsedAttr &AL) { + using llvm::Triple; Triple Target = S.Context.getTargetInfo().getTriple(); - if (Target.getEnvironment() != Triple::Compute) { + // FIXME: it is OK for a compute shader entry and pixel shader entry live in + // same HLSL file.Issue https://github.com/llvm/llvm-project/issues/57880. + if (Target.getEnvironment() != Triple::Compute && + Target.getEnvironment() != Triple::Library) { uint32_t Pipeline = (uint32_t)S.Context.getTargetInfo().getTriple().getEnvironment() - (uint32_t)llvm::Triple::Pixel; @@ -6895,7 +7040,25 @@ static void handleHLSLSVGroupIndexAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - D->addAttr(::new (S.Context) HLSLSV_GroupIndexAttr(S.Context, AL)); + // FIXME: report warning and ignore semantic when cannot apply on the Decl. + // See https://github.com/llvm/llvm-project/issues/57916. + + // FIXME: support semantic on field. + // See https://github.com/llvm/llvm-project/issues/57889. + if (isa<FieldDecl>(D)) { + S.Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_ast_node) + << AL << "parameter"; + return; + } + + auto *VD = cast<ValueDecl>(D); + if (!isLegalTypeForHLSLSV_DispatchThreadID(VD->getType())) { + S.Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type) + << AL << "uint/uint2/uint3"; + return; + } + + D->addAttr(::new (S.Context) HLSLSV_DispatchThreadIDAttr(S.Context, AL)); } static void handleHLSLShaderAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -6905,7 +7068,11 @@ static void handleHLSLShaderAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; HLSLShaderAttr::ShaderType ShaderType; - if (!HLSLShaderAttr::ConvertStrToShaderType(Str, ShaderType)) { + if (!HLSLShaderAttr::ConvertStrToShaderType(Str, ShaderType) || + // Library is added to help convert HLSLShaderAttr::ShaderType to + // llvm::Triple::EnviromentType. It is not a legal + // HLSLShaderAttr::ShaderType. + ShaderType == HLSLShaderAttr::Library) { S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << Str << ArgLoc; return; @@ -6931,6 +7098,78 @@ Sema::mergeHLSLShaderAttr(Decl *D, const AttributeCommonInfo &AL, return HLSLShaderAttr::Create(Context, ShaderType, AL); } +static void handleHLSLResourceBindingAttr(Sema &S, Decl *D, + const ParsedAttr &AL) { + StringRef Space = "space0"; + StringRef Slot = ""; + + if (!AL.isArgIdent(0)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL << AANT_ArgumentIdentifier; + return; + } + + IdentifierLoc *Loc = AL.getArgAsIdent(0); + StringRef Str = Loc->Ident->getName(); + SourceLocation ArgLoc = Loc->Loc; + + SourceLocation SpaceArgLoc; + if (AL.getNumArgs() == 2) { + Slot = Str; + if (!AL.isArgIdent(1)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL << AANT_ArgumentIdentifier; + return; + } + + IdentifierLoc *Loc = AL.getArgAsIdent(1); + Space = Loc->Ident->getName(); + SpaceArgLoc = Loc->Loc; + } else { + Slot = Str; + } + + // Validate. + if (!Slot.empty()) { + switch (Slot[0]) { + case 'u': + case 'b': + case 's': + case 't': + break; + default: + S.Diag(ArgLoc, diag::err_hlsl_unsupported_register_type) + << Slot.substr(0, 1); + return; + } + + StringRef SlotNum = Slot.substr(1); + unsigned Num = 0; + if (SlotNum.getAsInteger(10, Num)) { + S.Diag(ArgLoc, diag::err_hlsl_unsupported_register_number); + return; + } + } + + if (!Space.startswith("space")) { + S.Diag(SpaceArgLoc, diag::err_hlsl_expected_space) << Space; + return; + } + StringRef SpaceNum = Space.substr(5); + unsigned Num = 0; + if (SpaceNum.getAsInteger(10, Num)) { + S.Diag(SpaceArgLoc, diag::err_hlsl_expected_space) << Space; + return; + } + + // FIXME: check reg type match decl. Issue + // https://github.com/llvm/llvm-project/issues/57886. + HLSLResourceBindingAttr *NewAttr = + HLSLResourceBindingAttr::Create(S.getASTContext(), Slot, Space, AL); + if (NewAttr) + D->addAttr(NewAttr); +} + 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) @@ -7050,7 +7289,7 @@ static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } Expr *NumParamsExpr = static_cast<Expr *>(AL.getArgAsExpr(0)); - Optional<llvm::APSInt> NumParams = llvm::APSInt(32); + std::optional<llvm::APSInt> NumParams = llvm::APSInt(32); if (!(NumParams = NumParamsExpr->getIntegerConstantExpr(S.Context))) { S.Diag(AL.getLoc(), diag::err_attribute_argument_type) << AL << AANT_ArgumentIntegerConstant @@ -7252,7 +7491,7 @@ static void handleAVRSignalAttr(Sema &S, Decl *D, const ParsedAttr &AL) { static void handleBPFPreserveAIRecord(Sema &S, RecordDecl *RD) { // Add preserve_access_index attribute to all fields and inner records. - for (auto D : RD->decls()) { + for (auto *D : RD->decls()) { if (D->hasAttr<BPFPreserveAccessIndexAttr>()) continue; @@ -7874,8 +8113,8 @@ static void handleNoSanitizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { SanitizerName != "coverage") S.Diag(LiteralLoc, diag::warn_unknown_sanitizer_ignored) << SanitizerName; else if (isGlobalVar(D) && !isSanitizerAttributeAllowedOnGlobals(SanitizerName)) - S.Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) - << AL << ExpectedFunctionOrMethod; + S.Diag(D->getLocation(), diag::warn_attribute_type_not_supported_global) + << AL << SanitizerName; Sanitizers.push_back(SanitizerName); } @@ -8458,6 +8697,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_X86ForceAlignArgPointer: handleX86ForceAlignArgPointerAttr(S, D, AL); break; + case ParsedAttr::AT_ReadOnlyPlacement: + handleSimpleAttribute<ReadOnlyPlacementAttr>(S, D, AL); + break; case ParsedAttr::AT_DLLExport: case ParsedAttr::AT_DLLImport: handleDLLAttr(S, D, AL); @@ -8634,6 +8876,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_NoEscape: handleNoEscapeAttr(S, D, AL); break; + case ParsedAttr::AT_MaybeUndef: + handleSimpleAttribute<MaybeUndefAttr>(S, D, AL); + break; case ParsedAttr::AT_AssumeAligned: handleAssumeAlignedAttr(S, D, AL); break; @@ -8761,6 +9006,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_Target: handleTargetAttr(S, D, AL); break; + case ParsedAttr::AT_TargetVersion: + handleTargetVersionAttr(S, D, AL); + break; case ParsedAttr::AT_TargetClones: handleTargetClonesAttr(S, D, AL); break; @@ -8904,9 +9152,15 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_HLSLSV_GroupIndex: handleHLSLSVGroupIndexAttr(S, D, AL); break; + case ParsedAttr::AT_HLSLSV_DispatchThreadID: + handleHLSLSV_DispatchThreadIDAttr(S, D, AL); + break; case ParsedAttr::AT_HLSLShader: handleHLSLShaderAttr(S, D, AL); break; + case ParsedAttr::AT_HLSLResourceBinding: + handleHLSLResourceBindingAttr(S, D, AL); + break; case ParsedAttr::AT_AbiTag: handleAbiTagAttr(S, D, AL); |