diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
index fef34bd..30809a3 100644
--- a/include/clang/Basic/Attr.td
+++ b/include/clang/Basic/Attr.td
@@ -192,0 +193,3 @@ class Keyword<string name> : Spelling<name, "Keyword">;
+class Pragma<string namespace, string name> : Spelling<name, "Pragma"> {
+  string Namespace = namespace;
+}
@@ -1770,3 +1773 @@ def LoopHint : Attr {
-  /// FIXME: Add Pragma spelling to tablegen and
-  /// use it here.
-  let Spellings = [Keyword<"loop">];
+  let Spellings = [Pragma<"clang", "loop">];
@@ -1797,3 +1798,2 @@ def LoopHint : Attr {
-  // FIXME: Modify pretty printer to print this pragma.
-  void print(raw_ostream &OS, const PrintingPolicy &Policy) const {
-    OS << "#pragma clang loop " << getOptionName(option) << "(";
+  void printPrettyPragma(raw_ostream &OS, const PrintingPolicy &Policy) const {
+    OS << getOptionName(option) << "(";
diff --git a/include/clang/Basic/Attributes.h b/include/clang/Basic/Attributes.h
index 4a7e462..5783b3b 100644
--- a/include/clang/Basic/Attributes.h
+++ b/include/clang/Basic/Attributes.h
@@ -28 +28,3 @@ enum class AttrSyntax {
-  CXX
+  CXX,
+  // Is the identifier known as a pragma attribute?
+  Pragma
diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h
index 6872ccc..24e4cd4 100644
--- a/include/clang/Sema/AttributeList.h
+++ b/include/clang/Sema/AttributeList.h
@@ -83 +83,3 @@ public:
-    AS_Keyword
+    AS_Keyword,
+    /// #pragma ...
+    AS_Pragma
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 1daab32..3663cf3 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -171,2 +170,0 @@ void StmtPrinter::VisitAttributedStmt(AttributedStmt *Node) {
-  std::string raw_attr_os;
-  llvm::raw_string_ostream AttrOS(raw_attr_os);
@@ -174,6 +172 @@ void StmtPrinter::VisitAttributedStmt(AttributedStmt *Node) {
-    // FIXME: This hack will be removed when printPretty
-    // has been modified to print pretty pragmas
-    if (const LoopHintAttr *LHA = dyn_cast<LoopHintAttr>(Attr)) {
-      LHA->print(OS, Policy);
-    } else
-      Attr->printPretty(AttrOS, Policy);
+    Attr->printPretty(OS, Policy);
@@ -182,5 +174,0 @@ void StmtPrinter::VisitAttributedStmt(AttributedStmt *Node) {
-  // Print attributes after pragmas.
-  StringRef AttrStr = AttrOS.str();
-  if (!AttrStr.empty())
-    OS << AttrStr;
-
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index 210963e..48ed8ff 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -1784 +1783,0 @@ StmtResult Parser::ParsePragmaLoopHint(StmtVector &Stmts, bool OnlyStatement,
-    // FIXME: Replace AS_Keyword with Pragma spelling AS_Pragma.
@@ -1786 +1785 @@ StmtResult Parser::ParsePragmaLoopHint(StmtVector &Stmts, bool OnlyStatement,
-                     ArgHints, 3, AttributeList::AS_Keyword);
+                     ArgHints, 3, AttributeList::AS_Pragma);
diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp
index c03ff90..646022d 100644
--- a/utils/TableGen/ClangAttrEmitter.cpp
+++ b/utils/TableGen/ClangAttrEmitter.cpp
@@ -44 +44 @@ public:
-    if (V == "CXX11")
+    if (V == "CXX11" || V == "Pragma")
@@ -1056 +1056 @@ writePrettyPrintFunction(Record &R,
-  if (Spellings.size() == 0) {
+  if (Spellings.empty()) {
@@ -1083 +1083 @@ writePrettyPrintFunction(Record &R,
-      if (Namespace != "") {
+      if (!Namespace.empty()) {
@@ -1092,0 +1093,8 @@ writePrettyPrintFunction(Record &R,
+    } else if (Variety == "Pragma") {
+      Prefix = "#pragma ";
+      Suffix = "\n";
+      std::string Namespace = Spellings[I].nameSpace();
+      if (!Namespace.empty()) {
+        Spelling += Namespace;
+        Spelling += " ";
+      }
@@ -1102,0 +1111,8 @@ writePrettyPrintFunction(Record &R,
+    if (Variety == "Pragma") {
+      OS << " \";\n";
+      OS << "    printPrettyPragma(OS, Policy);\n";
+      OS << "    break;\n";
+      OS << "  }\n";
+      continue;
+    }
+
@@ -1783 +1799 @@ void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
-  std::vector<Record *> Declspec, GNU;
+  std::vector<Record *> Declspec, GNU, Pragma;
@@ -1796 +1812 @@ void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
-      else if (Variety == "CXX11") {
+      else if (Variety == "CXX11")
@@ -1798 +1814,2 @@ void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
-      }
+      else if (Variety == "Pragma")
+        Pragma.push_back(R);
@@ -1811,0 +1829,3 @@ void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
+  OS << "case AttrSyntax::Pragma:\n";
+  OS << "  return llvm::StringSwitch<bool>(Name)\n";
+  GenerateHasAttrSpellingStringSwitch(Pragma, OS, "Pragma");
@@ -1847,11 +1867,11 @@ void EmitClangAttrSpellingListIndex(RecordKeeper &Records, raw_ostream &OS) {
-      OS << "    if (Name == \""
-        << Spellings[I].name() << "\" && "
-        << "SyntaxUsed == "
-        << StringSwitch<unsigned>(Spellings[I].variety())
-          .Case("GNU", 0)
-          .Case("CXX11", 1)
-          .Case("Declspec", 2)
-          .Case("Keyword", 3)
-          .Default(0)
-        << " && Scope == \"" << Spellings[I].nameSpace() << "\")\n"
-        << "        return " << I << ";\n";
+      OS << "    if (Name == \"" << Spellings[I].name() << "\" && "
+         << "SyntaxUsed == "
+         << StringSwitch<unsigned>(Spellings[I].variety())
+                .Case("GNU", 0)
+                .Case("CXX11", 1)
+                .Case("Declspec", 2)
+                .Case("Keyword", 3)
+                .Case("Pragma", 4)
+                .Default(0)
+         << " && Scope == \"" << Spellings[I].nameSpace() << "\")\n"
+         << "        return " << I << ";\n";
@@ -2477 +2497 @@ void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) {
-  std::vector<StringMatcher::StringPair> GNU, Declspec, CXX11, Keywords;
+  std::vector<StringMatcher::StringPair> GNU, Declspec, CXX11, Keywords, Pragma;
@@ -2519,0 +2540,2 @@ void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) {
+        else if (Variety == "Pragma")
+          Matches = &Pragma;
@@ -2543,0 +2566,2 @@ void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) {
+  OS << "  } else if (AttributeList::AS_Pragma == Syntax) {\n";
+  StringMatcher("Name", Pragma, OS).Emit();
@@ -2649 +2673,2 @@ enum SpellingKind {
-  Keyword = 1 << 3
+  Keyword = 1 << 3,
+  Pragma = 1 << 4
@@ -2694,4 +2719,5 @@ static void WriteDocumentation(const DocumentationData &Doc,
-      .Case("GNU", GNU)
-      .Case("CXX11", CXX11)
-      .Case("Declspec", Declspec)
-      .Case("Keyword", Keyword);
+                            .Case("GNU", GNU)
+                            .Case("CXX11", CXX11)
+                            .Case("Declspec", Declspec)
+                            .Case("Keyword", Keyword)
+                            .Case("Pragma", Pragma);
@@ -2732 +2758,2 @@ static void WriteDocumentation(const DocumentationData &Doc,
-  OS << "   :header: \"GNU\", \"C++11\", \"__declspec\", \"Keyword\"\n\n";
+  OS << "   :header: \"GNU\", \"C++11\", \"__declspec\", \"Keyword\",";
+  OS << " \"Pragma\"\n\n";
@@ -2740,0 +2768,2 @@ static void WriteDocumentation(const DocumentationData &Doc,
+  OS << "\"\n\n";
+  if (SupportedSpellings & Pragma) OS << "X";
