Add [[clang::suppress(rule, ...)]] attribute

Summary:
This patch implements parsing of [[clang::suppress(rule, ...)]]
and [[gsl::suppress(rule, ...)]] attributes.

C++ Core Guidelines depend heavily on tool support for
rule enforcement. They also propose a way to suppress
warnings [1] which is by annotating any ancestor in AST
with the C++11 attribute [[gsl::suppress(rule1,...)]].
To have a mechanism to suppress non-C++ Core
Guidelines specific, an additional spelling of [[clang::suppress]]
is defined.

For example, to suppress the warning cppcoreguidelines-slicing,
one could do
```
[[clang::suppress("cppcoreguidelines-slicing")]]
void f() { ... code that does slicing ... }
```
or
```
void g() {
  Derived b;
  [[clang::suppress("cppcoreguidelines-slicing")]]
  Base a{b};
  [[clang::suppress("cppcoreguidelines-slicing")]] {
    doSomething();
    Base a2{b};
  }
}
```

This parsing can then be used by clang-tidy, which includes multiple
C++ Core Guidelines rules, to suppress warnings (see
https://reviews.llvm.org/D24888).
For the exact naming of the rule in the attribute, there
are different possibilities, which will be defined in the
corresponding clang-tidy patch.

Currently, clang-tidy supports suppressing of warnings through "//
NOLINT" comments. There are some advantages that the attribute has:
- Suppressing specific warnings instead of all warnings
- Suppressing warnings in a block (namespace, function, compound
  statement)
- Code formatting may split a statement into multiple lines,
  thus a "// NOLINT" comment may be on the wrong line

I'm looking forward to your comments!

[1] https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#inforce-enforcement

Reviewers: alexfh, aaron.ballman, rsmith

Subscribers: cfe-commits

Differential Revision: https://reviews.llvm.org/D24886

llvm-svn: 298880
diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp
index 01fa856..4ee3412 100644
--- a/clang/lib/Sema/SemaStmtAttr.cpp
+++ b/clang/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<StringRef> 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