Index: cfe/trunk/include/clang/Basic/Attr.td =================================================================== --- cfe/trunk/include/clang/Basic/Attr.td +++ cfe/trunk/include/clang/Basic/Attr.td @@ -1545,6 +1545,12 @@ let Documentation = [SwiftIndirectResultDocs]; } +def Suppress : StmtAttr { + let Spellings = [CXX11<"gsl", "suppress">]; + let Args = [VariadicStringArgument<"DiagnosticIdentifiers">]; + let Documentation = [SuppressDocs]; +} + def SysVABI : InheritableAttr { let Spellings = [GCC<"sysv_abi">]; // let Subjects = [Function, ObjCMethod]; Index: cfe/trunk/include/clang/Basic/AttrDocs.td =================================================================== --- cfe/trunk/include/clang/Basic/AttrDocs.td +++ cfe/trunk/include/clang/Basic/AttrDocs.td @@ -2771,6 +2771,32 @@ }]; } +def SuppressDocs : Documentation { + let Category = DocCatStmt; + let Content = [{ +The ``[[gsl::suppress]]`` attribute suppresses specific +clang-tidy diagnostics for rules of the `C++ Core Guidelines`_ in a portable +way. The attribute can be attached to declarations, statements, and at +namespace scope. + +.. code-block:: c++ + + [[gsl::suppress("Rh-public")]] + void f_() { + int *p; + [[gsl::suppress("type")]] { + p = reinterpret_cast(7); + } + } + namespace N { + [[clang::suppress("type", "bounds")]]; + ... + } + +.. _`C++ Core Guidelines`: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#inforce-enforcement + }]; +} + def AbiTagsDocs : Documentation { let Category = DocCatFunction; let Content = [{ Index: cfe/trunk/lib/Sema/SemaDeclAttr.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaDeclAttr.cpp +++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp @@ -4097,6 +4097,26 @@ } } +static void handleSuppressAttr(Sema &S, Decl *D, const AttributeList &Attr) { + if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) + return; + + std::vector DiagnosticIdentifiers; + for (unsigned I = 0, E = Attr.getNumArgs(); I != E; ++I) { + StringRef RuleName; + + if (!S.checkStringLiteralArgumentAttr(Attr, I, RuleName, nullptr)) + return; + + // FIXME: Warn if the rule name is unknown. This is tricky because only + // clang-tidy knows about available rules. + DiagnosticIdentifiers.push_back(RuleName); + } + D->addAttr(::new (S.Context) SuppressAttr( + Attr.getRange(), S.Context, DiagnosticIdentifiers.data(), + DiagnosticIdentifiers.size(), Attr.getAttributeSpellingListIndex())); +} + bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, const FunctionDecl *FD) { if (attr.isInvalid()) @@ -6156,6 +6176,9 @@ case AttributeList::AT_PreserveAll: handleCallConvAttr(S, D, Attr); break; + case AttributeList::AT_Suppress: + handleSuppressAttr(S, D, Attr); + break; case AttributeList::AT_OpenCLKernel: handleSimpleAttribute(S, D, Attr); break; Index: cfe/trunk/lib/Sema/SemaStmtAttr.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaStmtAttr.cpp +++ cfe/trunk/lib/Sema/SemaStmtAttr.cpp @@ -53,6 +53,31 @@ return ::new (S.Context) auto(Attr); } +static Attr *handleSuppressAttr(Sema &S, Stmt *St, const AttributeList &A, + SourceRange Range) { + if (A.getNumArgs() < 1) { + S.Diag(A.getLoc(), diag::err_attribute_too_few_arguments) + << A.getName() << 1; + return nullptr; + } + + std::vector DiagnosticIdentifiers; + for (unsigned I = 0, E = A.getNumArgs(); I != E; ++I) { + StringRef RuleName; + + if (!S.checkStringLiteralArgumentAttr(A, I, RuleName, nullptr)) + return nullptr; + + // FIXME: Warn if the rule name is unknown. This is tricky because only + // clang-tidy knows about available rules. + DiagnosticIdentifiers.push_back(RuleName); + } + + return ::new (S.Context) SuppressAttr( + A.getRange(), S.Context, DiagnosticIdentifiers.data(), + DiagnosticIdentifiers.size(), A.getAttributeSpellingListIndex()); +} + static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A, SourceRange) { IdentifierLoc *PragmaNameLoc = A.getArgAsIdent(0); @@ -279,6 +304,8 @@ return handleLoopHintAttr(S, St, A, Range); case AttributeList::AT_OpenCLUnrollHint: return handleOpenCLUnrollHint(S, St, A, Range); + case AttributeList::AT_Suppress: + return handleSuppressAttr(S, St, A, Range); default: // if we're here, then we parsed a known attribute, but didn't recognize // it as a statement attribute => it is declaration attribute Index: cfe/trunk/test/Misc/ast-dump-attr.cpp =================================================================== --- cfe/trunk/test/Misc/ast-dump-attr.cpp +++ cfe/trunk/test/Misc/ast-dump-attr.cpp @@ -179,3 +179,25 @@ __attribute__((external_source_symbol(generated_declaration, defined_in="module", language="Swift"))); // CHECK: FunctionDecl{{.*}} TestExternalSourceSymbolAttr5 // CHECK-NEXT: ExternalSourceSymbolAttr{{.*}} "Swift" "module" GeneratedDeclaration + +namespace TestSuppress { + [[gsl::suppress("at-namespace")]]; + // CHECK: NamespaceDecl{{.*}} TestSuppress + // CHECK-NEXT: EmptyDecl{{.*}} + // CHECK-NEXT: SuppressAttr{{.*}} at-namespace + [[gsl::suppress("on-decl")]] + void TestSuppressFunction(); + // CHECK: FunctionDecl{{.*}} TestSuppressFunction + // CHECK-NEXT SuppressAttr{{.*}} on-decl + + void f() { + int *i; + + [[gsl::suppress("on-stmt")]] { + // CHECK: AttributedStmt + // CHECK-NEXT: SuppressAttr{{.*}} on-stmt + // CHECK-NEXT: CompoundStmt + i = reinterpret_cast(7); + } + } +} Index: cfe/trunk/test/SemaCXX/suppress.cpp =================================================================== --- cfe/trunk/test/SemaCXX/suppress.cpp +++ cfe/trunk/test/SemaCXX/suppress.cpp @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -std=c++11 -fsyntax-only %s -verify + +[[gsl::suppress("globally")]]; + +namespace N { + [[gsl::suppress("in-a-namespace")]]; +} + +[[gsl::suppress("readability-identifier-naming")]] +void f_() { + int *p; + [[gsl::suppress("type", "bounds")]] { + p = reinterpret_cast(7); + } + + [[gsl::suppress]] int x; // expected-error {{'suppress' attribute takes at least 1 argument}} + [[gsl::suppress()]] int y; // expected-error {{'suppress' attribute takes at least 1 argument}} + int [[gsl::suppress("r")]] z; // expected-error {{'suppress' attribute cannot be applied to types}} + [[gsl::suppress(f_)]] float f; // expected-error {{'suppress' attribute requires a string}} +} + +union [[gsl::suppress("type.1")]] U { + int i; + float f; +};