Revert "Revert "Support for groups of attributes in #pragma clang attribute""

This reverts commit r345487, which reverted r345486. I think the crashes were
caused by an OOM on the builder, trying again to confirm...

llvm-svn: 345517
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index 8024e1a..f6ac9b4 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -520,9 +520,9 @@
 
 } // end anonymous namespace
 
-void Sema::ActOnPragmaAttributePush(ParsedAttr &Attribute,
-                                    SourceLocation PragmaLoc,
-                                    attr::ParsedSubjectMatchRuleSet Rules) {
+void Sema::ActOnPragmaAttributeAttribute(
+    ParsedAttr &Attribute, SourceLocation PragmaLoc,
+    attr::ParsedSubjectMatchRuleSet Rules) {
   SmallVector<attr::SubjectMatchRule, 4> SubjectMatchRules;
   // Gather the subject match rules that are supported by the attribute.
   SmallVector<std::pair<attr::SubjectMatchRule, bool>, 4>
@@ -622,48 +622,64 @@
     Diagnostic << attrMatcherRuleListToString(ExtraRules);
   }
 
-  PragmaAttributeStack.push_back(
+  if (PragmaAttributeStack.empty()) {
+    Diag(PragmaLoc, diag::err_pragma_attr_attr_no_push);
+    return;
+  }
+
+  PragmaAttributeStack.back().Entries.push_back(
       {PragmaLoc, &Attribute, std::move(SubjectMatchRules), /*IsUsed=*/false});
 }
 
+void Sema::ActOnPragmaAttributeEmptyPush(SourceLocation PragmaLoc) {
+  PragmaAttributeStack.emplace_back();
+  PragmaAttributeStack.back().Loc = PragmaLoc;
+}
+
 void Sema::ActOnPragmaAttributePop(SourceLocation PragmaLoc) {
   if (PragmaAttributeStack.empty()) {
     Diag(PragmaLoc, diag::err_pragma_attribute_stack_mismatch);
     return;
   }
-  const PragmaAttributeEntry &Entry = PragmaAttributeStack.back();
-  if (!Entry.IsUsed) {
-    assert(Entry.Attribute && "Expected an attribute");
-    Diag(Entry.Attribute->getLoc(), diag::warn_pragma_attribute_unused)
-        << Entry.Attribute->getName();
-    Diag(PragmaLoc, diag::note_pragma_attribute_region_ends_here);
+
+  for (const PragmaAttributeEntry &Entry :
+       PragmaAttributeStack.back().Entries) {
+    if (!Entry.IsUsed) {
+      assert(Entry.Attribute && "Expected an attribute");
+      Diag(Entry.Attribute->getLoc(), diag::warn_pragma_attribute_unused)
+          << Entry.Attribute->getName();
+      Diag(PragmaLoc, diag::note_pragma_attribute_region_ends_here);
+    }
   }
+
   PragmaAttributeStack.pop_back();
 }
 
 void Sema::AddPragmaAttributes(Scope *S, Decl *D) {
   if (PragmaAttributeStack.empty())
     return;
-  for (auto &Entry : PragmaAttributeStack) {
-    ParsedAttr *Attribute = Entry.Attribute;
-    assert(Attribute && "Expected an attribute");
+  for (auto &Group : PragmaAttributeStack) {
+    for (auto &Entry : Group.Entries) {
+      ParsedAttr *Attribute = Entry.Attribute;
+      assert(Attribute && "Expected an attribute");
 
-    // Ensure that the attribute can be applied to the given declaration.
-    bool Applies = false;
-    for (const auto &Rule : Entry.MatchRules) {
-      if (Attribute->appliesToDecl(D, Rule)) {
-        Applies = true;
-        break;
+      // Ensure that the attribute can be applied to the given declaration.
+      bool Applies = false;
+      for (const auto &Rule : Entry.MatchRules) {
+        if (Attribute->appliesToDecl(D, Rule)) {
+          Applies = true;
+          break;
+        }
       }
+      if (!Applies)
+        continue;
+      Entry.IsUsed = true;
+      PragmaAttributeCurrentTargetDecl = D;
+      ParsedAttributesView Attrs;
+      Attrs.addAtEnd(Attribute);
+      ProcessDeclAttributeList(S, D, Attrs);
+      PragmaAttributeCurrentTargetDecl = nullptr;
     }
-    if (!Applies)
-      continue;
-    Entry.IsUsed = true;
-    PragmaAttributeCurrentTargetDecl = D;
-    ParsedAttributesView Attrs;
-    Attrs.addAtEnd(Attribute);
-    ProcessDeclAttributeList(S, D, Attrs);
-    PragmaAttributeCurrentTargetDecl = nullptr;
   }
 }