Index: clang/include/clang/Basic/Attr.td =================================================================== --- clang/include/clang/Basic/Attr.td +++ clang/include/clang/Basic/Attr.td @@ -1147,6 +1147,12 @@ let Documentation = [FallthroughDocs]; } +def Likelihood : StmtAttr { + let Spellings = [CXX11<"", "likely", 201803>, Clang<"likely">, CXX11<"", "unlikely", 201803>, Clang<"unlikely">]; +// let Subjects = [Stmt, LabelStmt]; + let Documentation = [LikelihoodDocs]; +} + def FastCall : DeclOrTypeAttr { let Spellings = [GCC<"fastcall">, Keyword<"__fastcall">, Keyword<"_fastcall">]; Index: clang/include/clang/Basic/AttrDocs.td =================================================================== --- clang/include/clang/Basic/AttrDocs.td +++ clang/include/clang/Basic/AttrDocs.td @@ -1492,6 +1492,39 @@ }]; } +def LikelihoodDocs : Documentation { + let Category = DocCatStmt; + let Heading = "likely / unlikely"; + let Content = [{ + +The ``likely`` or ``unlikely`` attribute is used to annotate that a statement or label is likely or unlikely to executed + +Here is an example: + +.. code-block:: c++ + + void g(int); + int f(int n) { + if (n > 5) [[unlikely]] { // n > 5 is considered to be arbitrarily unlikely + g(0); + return n * 2 + 1; + } + + switch (n) { + case 1: + g(1); + [[fallthrough]]; + + [[likely]] case 2: // n == 2 is considered to be arbitrarily more + g(2); // likely than any other value of n + break; + } + return 3; + } + + }]; +} + def ARMInterruptDocs : Documentation { let Category = DocCatFunction; let Heading = "interrupt (ARM)"; Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -7339,6 +7339,8 @@ "use of the %0 attribute is a C++14 extension">, InGroup; def ext_cxx17_attr : Extension< "use of the %0 attribute is a C++17 extension">, InGroup; +def ext_cxx2a_attr : Extension< + "use of the %0 attribute is a C++2a extension">, InGroup; def warn_unused_comparison : Warning< "%select{equality|inequality|relational|three-way}0 comparison result unused">, @@ -8158,6 +8160,15 @@ "fallthrough annotation in unreachable code">, InGroup, DefaultIgnore; +def err_likelihood_outside_control_scope : Error< + "%0 attribute can only appear inside an if, while, for, switch or catch">; +def err_multiple_likelihood : Error< + "there can only be one %0 attribue in any attribute list">; +def err_mutuably_exclusive_likelihood : Error< + "%0 and %1 are mutually exclusive">; +def note_previous_likelihood : Note< + "previously used %0 attribue">; + def warn_unreachable_default : Warning< "default label in switch which covers all enumeration values">, InGroup, DefaultIgnore; Index: clang/lib/Sema/SemaStmtAttr.cpp =================================================================== --- clang/lib/Sema/SemaStmtAttr.cpp +++ clang/lib/Sema/SemaStmtAttr.cpp @@ -51,6 +51,31 @@ return ::new (S.Context) auto(Attr); } +static Attr *handleLikelihoodAttr(Sema &S, Stmt *St, const ParsedAttr &A, + SourceRange Range) { + LikelihoodAttr Attr(A.getRange(), S.Context, + A.getAttributeSpellingListIndex()); + + Scope* scope = S.getCurScope(); + Scope* previousScope = nullptr; + + if (scope) + previousScope = scope->getParent(); + + //check that ths attribute is used in an if, while, for, switch or catch + if (!previousScope || + !(previousScope->getFlags() & Scope::ControlScope) || + previousScope->getFlags() & Scope::SEHExceptScope || + previousScope->getFlags() & Scope::SEHTryScope || + previousScope->getFlags() & Scope::FnTryCatchScope) + S.Diag(A.getLoc(), diag::err_likelihood_outside_control_scope) << A.getName(); + + if (!S.getLangOpts().CPlusPlus2a) + S.Diag(A.getLoc(), diag::ext_cxx2a_attr) << A.getName(); + + return ::new (S.Context) auto(Attr); +} + static Attr *handleSuppressAttr(Sema &S, Stmt *St, const ParsedAttr &A, SourceRange Range) { if (A.getNumArgs() < 1) { @@ -201,7 +226,21 @@ } HintAttrs[] = {{nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}}; + //there can be only one likelyhood attribute + const Attr* likelihoodAttr = nullptr; + for (const auto *I : Attrs) { + if (llvm::isa(I)) { + if (likelihoodAttr) { + if (std::strcmp(I->getSpelling(), likelihoodAttr->getSpelling())) + S.Diag(I->getLocation(), diag::err_mutuably_exclusive_likelihood) << I->getSpelling() << likelihoodAttr->getSpelling(); + else + S.Diag(I->getLocation(), diag::err_multiple_likelihood) << I->getSpelling(); + S.Diag(likelihoodAttr->getLocation(), diag::note_previous_likelihood) << likelihoodAttr->getSpelling(); + } + likelihoodAttr = I; + } + const LoopHintAttr *LH = dyn_cast(I); // Skip non loop hint attributes @@ -336,6 +375,8 @@ return nullptr; case ParsedAttr::AT_FallThrough: return handleFallThroughAttr(S, St, A, Range); + case ParsedAttr::AT_Likelihood: + return handleLikelihoodAttr(S, St, A, Range); case ParsedAttr::AT_LoopHint: return handleLoopHintAttr(S, St, A, Range); case ParsedAttr::AT_OpenCLUnrollHint: Index: clang/test/SemaCXX/cxx2a-likelihood-attr.cpp =================================================================== --- /dev/null +++ clang/test/SemaCXX/cxx2a-likelihood-attr.cpp @@ -0,0 +1,51 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++2a + +int f(int i) { + if (i == 1) [[unlikely]] + { + return 0; + } + else if (i == 2) [[likely]] + return 1; + return 3; +} + +[[likely]] typedef int n1; // expected-error {{'likely' attribute cannot be applied to a declaration}} +typedef int [[likely]] n2; // expected-error {{'likely' attribute cannot be applied to types}} +typedef int n3 [[likely]]; // expected-error {{'likely' attribute cannot be applied to a declaration}} + +enum [[likely]] E { // expected-error {{'likely' attribute cannot be applied to a declaration}} + One +}; + +[[likely]] // expected-error {{'likely' attribute cannot be applied to a declaration}} + +void test(int i) { + [[likely]] // expected-error {{'likely' attribute can only appear in if, while, switch and for}} + if (1) [[likely, likely]] { + // expected-error@-1 {{there can only be one likely attribue in any attribute list}} + // expected-note@-2 {{previously used likely attribue}} + [[unlikely]] return ; // expected-error {{'unlikely' attribute can only appear in if, while, switch and for}} + } + else [[unlikely]] if (1) { + while (1) [[likely]] { + switch (i) { + [[likely]] case 1: + default: [[likely]] + return ; + } + } + for (;;) [[likely, unlikely]] + // expected-error@-1 {{unlikely and likely are mutually exclusive}} + // expected-note@-2 {{previously used likely attribue}} + [[likely]] return ; + // expected-error@-1 {{likely and unlikely are mutually exclusive}} + // expected-note@-5 {{previously used unlikely attribue}} + } + try { // expected-error {{cannot use 'try' with exceptions disabled}} + [[likely]]; // expected-error {{'likely' attribute can only appear in if, while, switch and for}} + } catch (int) { + [[likely]] test: // expected-error {{'likely' attribute cannot be applied to a declaration}} + [[unlikely]] return ; + } +} \ No newline at end of file