diff options
Diffstat (limited to 'clang/lib/Sema/SemaDeclAttr.cpp')
-rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 161 |
1 files changed, 145 insertions, 16 deletions
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index ef889a36bd55..4df8687aff89 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -1965,6 +1965,28 @@ static void handleRestrictAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } static void handleCPUSpecificAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + // Ensure we don't combine these with themselves, since that causes some + // confusing behavior. + if (AL.getParsedKind() == ParsedAttr::AT_CPUDispatch) { + if (checkAttrMutualExclusion<CPUSpecificAttr>(S, D, AL)) + return; + + if (const auto *Other = D->getAttr<CPUDispatchAttr>()) { + S.Diag(AL.getLoc(), diag::err_disallowed_duplicate_attribute) << AL; + S.Diag(Other->getLocation(), diag::note_conflicting_attribute); + return; + } + } else if (AL.getParsedKind() == ParsedAttr::AT_CPUSpecific) { + if (checkAttrMutualExclusion<CPUDispatchAttr>(S, D, AL)) + return; + + if (const auto *Other = D->getAttr<CPUSpecificAttr>()) { + S.Diag(AL.getLoc(), diag::err_disallowed_duplicate_attribute) << AL; + S.Diag(Other->getLocation(), diag::note_conflicting_attribute); + return; + } + } + FunctionDecl *FD = cast<FunctionDecl>(D); if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) { @@ -3211,54 +3233,57 @@ static void handleCodeSegAttr(Sema &S, Decl *D, const ParsedAttr &AL) { bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) { enum FirstParam { Unsupported, Duplicate, Unknown }; enum SecondParam { None, Architecture, Tune }; + enum ThirdParam { Target, TargetClones }; if (AttrStr.contains("fpmath=")) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) - << Unsupported << None << "fpmath="; + << Unsupported << None << "fpmath=" << Target; // Diagnose use of tune if target doesn't support it. if (!Context.getTargetInfo().supportsTargetAttributeTune() && AttrStr.contains("tune=")) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) - << Unsupported << None << "tune="; + << Unsupported << None << "tune=" << Target; ParsedTargetAttr ParsedAttrs = TargetAttr::parse(AttrStr); if (!ParsedAttrs.Architecture.empty() && !Context.getTargetInfo().isValidCPUName(ParsedAttrs.Architecture)) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) - << Unknown << Architecture << ParsedAttrs.Architecture; + << Unknown << Architecture << ParsedAttrs.Architecture << Target; if (!ParsedAttrs.Tune.empty() && !Context.getTargetInfo().isValidCPUName(ParsedAttrs.Tune)) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) - << Unknown << Tune << ParsedAttrs.Tune; + << Unknown << Tune << ParsedAttrs.Tune << Target; if (ParsedAttrs.DuplicateArchitecture) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) - << Duplicate << None << "arch="; + << Duplicate << None << "arch=" << Target; if (ParsedAttrs.DuplicateTune) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) - << Duplicate << None << "tune="; + << Duplicate << None << "tune=" << Target; for (const auto &Feature : ParsedAttrs.Features) { auto CurFeature = StringRef(Feature).drop_front(); // remove + or -. if (!Context.getTargetInfo().isValidFeatureName(CurFeature)) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) - << Unsupported << None << CurFeature; + << Unsupported << None << CurFeature << Target; } TargetInfo::BranchProtectionInfo BPI; - StringRef Error; - if (!ParsedAttrs.BranchProtection.empty() && - !Context.getTargetInfo().validateBranchProtection( - ParsedAttrs.BranchProtection, BPI, Error)) { - if (Error.empty()) + StringRef DiagMsg; + if (ParsedAttrs.BranchProtection.empty()) + return false; + if (!Context.getTargetInfo().validateBranchProtection( + ParsedAttrs.BranchProtection, BPI, DiagMsg)) { + if (DiagMsg.empty()) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) - << Unsupported << None << "branch-protection"; - else - return Diag(LiteralLoc, diag::err_invalid_branch_protection_spec) - << Error; + << Unsupported << None << "branch-protection" << Target; + return Diag(LiteralLoc, diag::err_invalid_branch_protection_spec) + << DiagMsg; } + if (!DiagMsg.empty()) + Diag(LiteralLoc, diag::warn_unsupported_branch_protection_spec) << DiagMsg; return false; } @@ -3274,6 +3299,107 @@ 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) { + enum FirstParam { Unsupported, Duplicate, Unknown }; + enum SecondParam { None, Architecture, Tune }; + enum ThirdParam { Target, TargetClones }; + HasCommas = HasCommas || Str.contains(','); + // Warn on empty at the beginning of a string. + if (Str.size() == 0) + return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) + << Unsupported << None << "" << TargetClones; + + std::pair<StringRef, StringRef> Parts = {{}, Str}; + while (!Parts.second.empty()) { + Parts = Parts.second.split(','); + StringRef Cur = Parts.first.trim(); + SourceLocation CurLoc = Literal->getLocationOfByte( + Cur.data() - Literal->getString().data(), getSourceManager(), + getLangOpts(), Context.getTargetInfo()); + + bool DefaultIsDupe = 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))) + 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::find(Strings, Cur) != Strings.end() || 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); + } + + if (Str.rtrim().endswith(",")) + return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) + << Unsupported << None << "" << TargetClones; + return false; +} + +static void handleTargetClonesAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + // Ensure we don't combine these with themselves, since that causes some + // confusing behavior. + if (const auto *Other = D->getAttr<TargetClonesAttr>()) { + S.Diag(AL.getLoc(), diag::err_disallowed_duplicate_attribute) << AL; + S.Diag(Other->getLocation(), diag::note_conflicting_attribute); + return; + } + if (checkAttrMutualExclusion<TargetClonesAttr>(S, D, AL)) + return; + + SmallVector<StringRef, 2> Strings; + bool HasCommas = false, HasDefault = false; + + for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) { + StringRef CurStr; + SourceLocation LiteralLoc; + if (!S.checkStringLiteralArgumentAttr(AL, I, CurStr, &LiteralLoc) || + S.checkTargetClonesAttrString( + LiteralLoc, CurStr, + cast<StringLiteral>(AL.getArgAsExpr(I)->IgnoreParenCasts()), + HasDefault, HasCommas, Strings)) + return; + } + + if (HasCommas && AL.getNumArgs() > 1) + S.Diag(AL.getLoc(), diag::warn_target_clone_mixed_values); + + if (!HasDefault) { + S.Diag(AL.getLoc(), diag::err_target_clone_must_have_default); + return; + } + + // FIXME: We could probably figure out how to get this to work for lambdas + // someday. + if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) { + if (MD->getParent()->isLambda()) { + S.Diag(D->getLocation(), diag::err_multiversion_doesnt_support) + << static_cast<unsigned>(MultiVersionKind::TargetClones) + << /*Lambda*/ 9; + return; + } + } + + cast<FunctionDecl>(D)->setIsMultiVersion(); + TargetClonesAttr *NewAttr = ::new (S.Context) + TargetClonesAttr(S.Context, AL, Strings.data(), Strings.size()); + D->addAttr(NewAttr); +} + static void handleMinVectorWidthAttr(Sema &S, Decl *D, const ParsedAttr &AL) { Expr *E = AL.getArgAsExpr(0); uint32_t VecWidth; @@ -8217,6 +8343,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_Target: handleTargetAttr(S, D, AL); break; + case ParsedAttr::AT_TargetClones: + handleTargetClonesAttr(S, D, AL); + break; case ParsedAttr::AT_MinVectorWidth: handleMinVectorWidthAttr(S, D, AL); break; |