diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -2216,6 +2216,12 @@ let Documentation = [SuppressDocs]; } +def HardenMisspeculation : StmtAttr { + let Spellings = [Clang<"harden_misspeculation">]; + let Args = [VariadicIdentifierArgument<"VariablesToHarden">]; + let Documentation = [HardenMisspeculationDocs]; +} + def SysVABI : DeclOrTypeAttr { let Spellings = [GCC<"sysv_abi">]; // let Subjects = [Function, ObjCMethod]; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -3873,6 +3873,13 @@ }]; } +def HardenMisspeculationDocs : Documentation { + let Category = DocCatStmt; + let Content = [{ +TODO(zbrid): Add documentation + }]; +} + def AbiTagsDocs : Documentation { let Category = DocCatFunction; let Content = [{ diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9155,6 +9155,10 @@ "fallthrough annotation in unreachable code">, InGroup, DefaultIgnore; +def err_harden_misspeculation_attr_wrong_target + : Error<"%0 attribute is only allowed on compound statements (ie block " + "statements)">; + def warn_unreachable_default : Warning< "default label in switch which covers all enumeration values">, InGroup, DefaultIgnore; diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp --- a/clang/lib/Sema/SemaStmtAttr.cpp +++ b/clang/lib/Sema/SemaStmtAttr.cpp @@ -10,14 +10,16 @@ // //===----------------------------------------------------------------------===// -#include "clang/AST/EvaluatedExprVisitor.h" -#include "clang/Sema/SemaInternal.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/EvaluatedExprVisitor.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Sema/DelayedDiagnostic.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/SemaInternal.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/Triple.h" using namespace clang; using namespace sema; @@ -51,6 +53,38 @@ return ::new (S.Context) FallThroughAttr(S.Context, A); } +static Attr *handleHardenMisspeculationAttr(Sema &S, Stmt *St, + const ParsedAttr &A, + SourceRange Range) { + if (!isa(St)) { + S.Diag(A.getRange().getBegin(), + diag::err_harden_misspeculation_attr_wrong_target) + << A << St->getBeginLoc(); + } + + // FIXME: Support non-x86_64 targets + if (!(S.Context.getTargetInfo().getTriple().getArch() == + llvm::Triple::ArchType::x86_64)) { + S.Diag(A.getLoc(), diag::err_attribute_unsupported) << A; + return nullptr; + } + + if (A.getNumArgs() < 1) { + S.Diag(A.getLoc(), diag::err_attribute_too_few_arguments) << A << 1; + return nullptr; + } + + for (unsigned I = 0, E = A.getNumArgs(); I != E; ++I) { + if (!A.isArgIdent(I)) { + S.Diag(A.getLoc(), diag::err_attribute_argument_type) + << A << AANT_ArgumentIdentifier; + return nullptr; + } + } + + return ::new (S.Context) HardenMisspeculationAttr(S.Context, A); +} + static Attr *handleSuppressAttr(Sema &S, Stmt *St, const ParsedAttr &A, SourceRange Range) { if (A.getNumArgs() < 1) { @@ -374,6 +408,8 @@ return handleOpenCLUnrollHint(S, St, A, Range); case ParsedAttr::AT_Suppress: return handleSuppressAttr(S, St, A, Range); + case ParsedAttr::AT_HardenMisspeculation: + return handleHardenMisspeculationAttr(S, St, A, Range); case ParsedAttr::AT_NoMerge: return handleNoMergeAttr(S, St, A, Range); default: diff --git a/clang/test/SemaCXX/attr-harden-misspeculation-unsupported-target.cpp b/clang/test/SemaCXX/attr-harden-misspeculation-unsupported-target.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/attr-harden-misspeculation-unsupported-target.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -std=c++11 -triple armv7 -fsyntax-only %s -verify + +int b(int a, int b) { + if (a < b) + [[clang::harden_misspeculation(a)]] { // expected-error {{'harden_misspeculation' attribute is not supported for this target}} + return a; + } + return b; +} diff --git a/clang/test/SemaCXX/attr-harden-misspeculation.cpp b/clang/test/SemaCXX/attr-harden-misspeculation.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/attr-harden-misspeculation.cpp @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -std=c++11 -fsyntax-only %s -verify + +int b(int a, int b) { + if (a < b) + [[clang::harden_misspeculation]] { // expected-error {{'harden_misspeculation' attribute takes at least 1 argument}} + a += 2; + } + + if (a == b) + [[clang::harden_misspeculation(1)]] { // expected-error {{'harden_misspeculation' attribute requires an identifier}} + a += 1; + } + + if (a > b) + [[clang::harden_misspeculation(a)]] // expected-error {{'harden_misspeculation' attribute is only allowed on compound statements (ie block statements)}} + return a; + + return a; +}