[cfe-commits] r158661 - in /cfe/trunk: include/clang/Basic/Attr.td include/clang/Sema/AttributeList.h lib/Parse/ParseDecl.cpp lib/Parse/ParseDeclCXX.cpp lib/Sema/AttributeList.cpp lib/Sema/SemaStmtAttr.cpp lib/Sema/SemaType.cpp test/SemaCXX/switch-implicit-fallthrough-per-method.cpp utils/TableGen/ClangAttrEmitter.cpp

Sean Hunt scshunt at csclub.uwaterloo.ca
Mon Jun 18 09:13:53 PDT 2012


Author: coppro
Date: Mon Jun 18 11:13:52 2012
New Revision: 158661

URL: http://llvm.org/viewvc/llvm-project?rev=158661&view=rev
Log:
Handle C++11 attribute namespaces automatically.

Now, as long as the 'Namespaces' variable is correct inside Attr.td, the
generated code will correctly admit a C++11 attribute only when it has the
appropriate namespace(s).

Modified:
    cfe/trunk/include/clang/Basic/Attr.td
    cfe/trunk/include/clang/Sema/AttributeList.h
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Parse/ParseDeclCXX.cpp
    cfe/trunk/lib/Sema/AttributeList.cpp
    cfe/trunk/lib/Sema/SemaStmtAttr.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/test/SemaCXX/switch-implicit-fallthrough-per-method.cpp
    cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp

Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=158661&r1=158660&r2=158661&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Mon Jun 18 11:13:52 2012
@@ -320,8 +320,9 @@
 }
 
 def FallThrough : Attr {
-  let Spellings = ["clang___fallthrough"];
-  let Subjects = [CaseStmt, DefaultStmt];
+  let Namespaces = ["clang"];
+  let Spellings = ["fallthrough"];
+  let Subjects = [NullStmt];
 }
 
 def FastCall : InheritableAttr {
@@ -850,4 +851,4 @@
 
 def VirtualInheritance : InheritableAttr {
   let Spellings = ["__virtual_inheritance"];
-}
\ No newline at end of file
+}

Modified: cfe/trunk/include/clang/Sema/AttributeList.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/AttributeList.h?rev=158661&r1=158660&r2=158661&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/AttributeList.h (original)
+++ cfe/trunk/include/clang/Sema/AttributeList.h Mon Jun 18 11:13:52 2012
@@ -52,6 +52,13 @@
 /// 4: __attribute__(( aligned(16) )). ParmName is unused, Args/Num used.
 ///
 class AttributeList { // TODO: This should really be called ParsedAttribute
+public:
+  /// The style used to specify an attribute.
+  enum Syntax {
+    AS_GNU,
+    AS_CXX11,
+    AS_Declspec
+  };
 private:
   IdentifierInfo *AttrName;
   IdentifierInfo *ScopeName;
@@ -64,11 +71,8 @@
   /// The expressions themselves are stored after the object.
   unsigned NumArgs : 16;
 
-  /// True if Microsoft style: declspec(foo).
-  unsigned DeclspecAttribute : 1;
-
-  /// True if C++0x-style: [[foo]].
-  unsigned CXX0XAttribute : 1;
+  /// Corresponds to the Syntax enum.
+  unsigned SyntaxUsed : 2;
 
   /// True if already diagnosed as invalid.
   mutable unsigned Invalid : 1;
@@ -123,15 +127,14 @@
                 IdentifierInfo *scopeName, SourceLocation scopeLoc,
                 IdentifierInfo *parmName, SourceLocation parmLoc,
                 Expr **args, unsigned numArgs,
-                bool declspec, bool cxx0x)
+                Syntax syntaxUsed)
     : AttrName(attrName), ScopeName(scopeName), ParmName(parmName),
       AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(parmLoc),
-      NumArgs(numArgs),
-      DeclspecAttribute(declspec), CXX0XAttribute(cxx0x), Invalid(false),
+      NumArgs(numArgs), SyntaxUsed(syntaxUsed), Invalid(false),
       UsedAsTypeAttr(false), IsAvailability(false), 
       NextInPosition(0), NextInPool(0) {
     if (numArgs) memcpy(getArgsBuffer(), args, numArgs * sizeof(Expr*));
-    AttrKind = getKind(getName(), getScopeName());
+    AttrKind = getKind(getName(), getScopeName(), syntaxUsed);
   }
 
   AttributeList(IdentifierInfo *attrName, SourceRange attrRange,
@@ -142,17 +145,17 @@
                 const AvailabilityChange &obsoleted,
                 SourceLocation unavailable, 
                 const Expr *messageExpr,
-                bool declspec, bool cxx0x)
+                Syntax syntaxUsed)
     : AttrName(attrName), ScopeName(scopeName), ParmName(parmName),
       AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(parmLoc),
-      NumArgs(0), DeclspecAttribute(declspec), CXX0XAttribute(cxx0x),
+      NumArgs(0), SyntaxUsed(syntaxUsed),
       Invalid(false), UsedAsTypeAttr(false), IsAvailability(true),
       UnavailableLoc(unavailable), MessageExpr(messageExpr),
       NextInPosition(0), NextInPool(0) {
     new (&getAvailabilitySlot(IntroducedSlot)) AvailabilityChange(introduced);
     new (&getAvailabilitySlot(DeprecatedSlot)) AvailabilityChange(deprecated);
     new (&getAvailabilitySlot(ObsoletedSlot)) AvailabilityChange(obsoleted);
-    AttrKind = getKind(getName(), getScopeName());
+    AttrKind = getKind(getName(), getScopeName(), syntaxUsed);
   }
 
   friend class AttributePool;
@@ -178,8 +181,8 @@
   IdentifierInfo *getParameterName() const { return ParmName; }
   SourceLocation getParameterLoc() const { return ParmLoc; }
 
-  bool isDeclspecAttribute() const { return DeclspecAttribute; }
-  bool isCXX0XAttribute() const { return CXX0XAttribute; }
+  bool isDeclspecAttribute() const { return SyntaxUsed == AS_Declspec; }
+  bool isCXX0XAttribute() const { return SyntaxUsed == AS_CXX11; }
 
   bool isInvalid() const { return Invalid; }
   void setInvalid(bool b = true) const { Invalid = b; }
@@ -188,7 +191,8 @@
   void setUsedAsTypeAttr() { UsedAsTypeAttr = true; }
 
   Kind getKind() const { return Kind(AttrKind); }
-  static Kind getKind(const IdentifierInfo *Name, const IdentifierInfo *Scope);
+  static Kind getKind(const IdentifierInfo *Name, const IdentifierInfo *Scope,
+                      Syntax SyntaxUsed);
 
   AttributeList *getNext() const { return NextInPosition; }
   void setNext(AttributeList *N) { NextInPosition = N; }
@@ -372,14 +376,13 @@
                         IdentifierInfo *scopeName, SourceLocation scopeLoc,
                         IdentifierInfo *parmName, SourceLocation parmLoc,
                         Expr **args, unsigned numArgs,
-                        bool declspec = false, bool cxx0x = false) {
+                        AttributeList::Syntax syntax) {
     void *memory = allocate(sizeof(AttributeList)
                             + numArgs * sizeof(Expr*));
     return add(new (memory) AttributeList(attrName, attrRange,
                                           scopeName, scopeLoc,
                                           parmName, parmLoc,
-                                          args, numArgs,
-                                          declspec, cxx0x));
+                                          args, numArgs, syntax));
   }
 
   AttributeList *create(IdentifierInfo *attrName, SourceRange attrRange,
@@ -390,14 +393,13 @@
                         const AvailabilityChange &obsoleted,
                         SourceLocation unavailable,
                         const Expr *MessageExpr,
-                        bool declspec = false, bool cxx0x = false) {
+                        AttributeList::Syntax syntax) {
     void *memory = allocate(AttributeFactory::AvailabilityAllocSize);
     return add(new (memory) AttributeList(attrName, attrRange,
                                           scopeName, scopeLoc,
                                           parmName, parmLoc,
                                           introduced, deprecated, obsoleted,
-                                          unavailable, MessageExpr,
-                                          declspec, cxx0x));
+                                          unavailable, MessageExpr, syntax));
   }
 
   AttributeList *createIntegerAttribute(ASTContext &C, IdentifierInfo *Name,
@@ -499,10 +501,10 @@
                         IdentifierInfo *scopeName, SourceLocation scopeLoc,
                         IdentifierInfo *parmName, SourceLocation parmLoc,
                         Expr **args, unsigned numArgs,
-                        bool declspec = false, bool cxx0x = false) {
+                        AttributeList::Syntax syntax) {
     AttributeList *attr =
       pool.create(attrName, attrRange, scopeName, scopeLoc, parmName, parmLoc,
-                  args, numArgs, declspec, cxx0x);
+                  args, numArgs, syntax);
     add(attr);
     return attr;
   }
@@ -515,12 +517,11 @@
                         const AvailabilityChange &obsoleted,
                         SourceLocation unavailable,
                         const Expr *MessageExpr,
-                        bool declspec = false, bool cxx0x = false) {
+                        AttributeList::Syntax syntax) {
     AttributeList *attr =
       pool.create(attrName, attrRange, scopeName, scopeLoc, parmName, parmLoc,
                   introduced, deprecated, obsoleted, unavailable,
-                  MessageExpr,
-                  declspec, cxx0x);
+                  MessageExpr, syntax);
     add(attr);
     return attr;
   }

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=158661&r1=158660&r2=158661&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Mon Jun 18 11:13:52 2012
@@ -159,7 +159,7 @@
         }
       } else {
         attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
-                     0, SourceLocation(), 0, 0);
+                     0, SourceLocation(), 0, 0, AttributeList::AS_GNU);
       }
     }
     if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen))
@@ -275,7 +275,8 @@
   if (!ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) {
     AttributeList *attr =
       Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), 0, AttrNameLoc,
-                   ParmName, ParmLoc, ArgExprs.take(), ArgExprs.size());
+                   ParmName, ParmLoc, ArgExprs.take(), ArgExprs.size(),
+                   AttributeList::AS_GNU);
     if (BuiltinType && attr->getKind() == AttributeList::AT_iboutletcollection)
       Diag(Tok, diag::err_iboutletcollection_builtintype);
   }
@@ -319,13 +320,14 @@
       if (!ArgExpr.isInvalid()) {
         Expr *ExprList = ArgExpr.take();
         attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
-                     SourceLocation(), &ExprList, 1, true);
+                     SourceLocation(), &ExprList, 1,
+                     AttributeList::AS_Declspec);
       }
       if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen))
         SkipUntil(tok::r_paren, false);
     } else {
       attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
-                   0, SourceLocation(), 0, 0, true);
+                   0, SourceLocation(), 0, 0, AttributeList::AS_Declspec);
     }
   }
   if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen))
@@ -344,7 +346,7 @@
     IdentifierInfo *AttrName = Tok.getIdentifierInfo();
     SourceLocation AttrNameLoc = ConsumeToken();
     attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
-                 SourceLocation(), 0, 0, true);
+                 SourceLocation(), 0, 0, AttributeList::AS_Declspec);
   }
 }
 
@@ -354,7 +356,7 @@
     IdentifierInfo *AttrName = Tok.getIdentifierInfo();
     SourceLocation AttrNameLoc = ConsumeToken();
     attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
-                 SourceLocation(), 0, 0, true);
+                 SourceLocation(), 0, 0, AttributeList::AS_Declspec);
   }
 }
 
@@ -364,7 +366,7 @@
     SourceLocation AttrNameLoc = ConsumeToken();
     attrs.addNew(PP.getIdentifierInfo("opencl_kernel_function"),
                  AttrNameLoc, 0, AttrNameLoc, 0,
-                 SourceLocation(), 0, 0, false);
+                 SourceLocation(), 0, 0, AttributeList::AS_GNU);
   }
 }
 
@@ -700,7 +702,7 @@
                Changes[Deprecated],
                Changes[Obsoleted], 
                UnavailableLoc, MessageExpr.take(),
-               false, false);
+               AttributeList::AS_GNU);
 }
 
 
@@ -905,7 +907,7 @@
   // Match the ')'.
   if (ArgExprsOk && !T.consumeClose()) {
     Attrs.addNew(&AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(),
-                 ArgExprs.take(), ArgExprs.size());
+                 ArgExprs.take(), ArgExprs.size(), AttributeList::AS_GNU);
   }
   if (EndLoc)
     *EndLoc = T.getCloseLocation();
@@ -1874,7 +1876,8 @@
   ExprVector ArgExprs(Actions);
   ArgExprs.push_back(ArgExpr.release());
   Attrs.addNew(PP.getIdentifierInfo("aligned"), KWLoc, 0, KWLoc,
-               0, T.getOpenLocation(), ArgExprs.take(), 1, false, true);
+               0, T.getOpenLocation(), ArgExprs.take(), 1,
+               AttributeList::AS_CXX11);
 }
 
 /// ParseDeclarationSpecifiers
@@ -2255,8 +2258,10 @@
       isInvalid = DS.SetFunctionSpecInline(Loc, PrevSpec, DiagID);
       IdentifierInfo *AttrName = Tok.getIdentifierInfo();
       SourceLocation AttrNameLoc = ConsumeToken();
+      // FIXME: This does not work correctly if it is set to be a declspec
+      //        attribute, and a GNU attribute is simply incorrect.
       DS.getAttributes().addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
-                                SourceLocation(), 0, 0);
+                                SourceLocation(), 0, 0, AttributeList::AS_GNU);
       continue;
     }
 

Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=158661&r1=158660&r2=158661&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Mon Jun 18 11:13:52 2012
@@ -907,7 +907,7 @@
     IdentifierInfo *AttrName = Tok.getIdentifierInfo();
     SourceLocation AttrNameLoc = ConsumeToken();
     attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
-                 SourceLocation(), 0, 0, false);
+                 SourceLocation(), 0, 0, AttributeList::AS_GNU);
   }
 }
 
@@ -2899,12 +2899,13 @@
     }
 
     bool AttrParsed = false;
-    switch (AttributeList::getKind(AttrName, ScopeName)) {
+    switch (AttributeList::getKind(AttrName, ScopeName,
+                                   AttributeList::AS_CXX11)) {
     // No arguments
     case AttributeList::AT_carries_dependency:
     // FIXME: implement generic support of attributes with C++11 syntax
     // see Parse/ParseDecl.cpp: ParseGNUAttributes
-    case AttributeList::AT_clang___fallthrough:
+    case AttributeList::AT_fallthrough:
     case AttributeList::AT_noreturn: {
       if (Tok.is(tok::l_paren)) {
         Diag(Tok.getLocation(), diag::err_cxx11_attribute_forbids_arguments)
@@ -2916,7 +2917,7 @@
                    SourceRange(ScopeLoc.isValid() ? ScopeLoc : AttrLoc,
                                AttrLoc),
                    ScopeName, ScopeLoc, 0,
-                   SourceLocation(), 0, 0, false, true);
+                   SourceLocation(), 0, 0, AttributeList::AS_CXX11);
       AttrParsed = true;
       break;
     }

Modified: cfe/trunk/lib/Sema/AttributeList.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AttributeList.cpp?rev=158661&r1=158660&r2=158661&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/AttributeList.cpp (original)
+++ cfe/trunk/lib/Sema/AttributeList.cpp Mon Jun 18 11:13:52 2012
@@ -95,13 +95,15 @@
                                       SourceLocation TokLoc, int Arg) {
   Expr *IArg = IntegerLiteral::Create(C, llvm::APInt(32, (uint64_t) Arg),
                                       C.IntTy, TokLoc);
-  return create(Name, TokLoc, 0, TokLoc, 0, TokLoc, &IArg, 1, 0);
+  return create(Name, TokLoc, 0, TokLoc, 0, TokLoc, &IArg, 1,
+                AttributeList::AS_GNU);
 }
 
 #include "clang/Sema/AttrParsedAttrKinds.inc"
 
 AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name,
-                                           const IdentifierInfo *ScopeName) {
+                                           const IdentifierInfo *ScopeName,
+                                           Syntax SyntaxUsed) {
   StringRef AttrName = Name->getName();
 
   // Normalize the attribute name, __foo__ becomes foo.
@@ -109,10 +111,14 @@
       AttrName.size() >= 4)
     AttrName = AttrName.substr(2, AttrName.size() - 4);
 
-  // FIXME: implement attribute namespacing correctly.
   SmallString<64> Buf;
   if (ScopeName)
-    AttrName = ((Buf += ScopeName->getName()) += "___") += AttrName;
+    Buf += ScopeName->getName();
+  // Ensure that in the case of C++11 attributes, we look for '::foo' if it is
+  // unscoped.
+  if (ScopeName || SyntaxUsed == AS_CXX11)
+    Buf += "::";
+  Buf += AttrName;
 
-  return ::getAttrKind(AttrName);
+  return ::getAttrKind(Buf);
 }

Modified: cfe/trunk/lib/Sema/SemaStmtAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmtAttr.cpp?rev=158661&r1=158660&r2=158661&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmtAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmtAttr.cpp Mon Jun 18 11:13:52 2012
@@ -48,7 +48,7 @@
 static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A,
                                   SourceRange Range) {
   switch (A.getKind()) {
-  case AttributeList::AT_clang___fallthrough:
+  case AttributeList::AT_fallthrough:
     return handleFallThroughAttr(S, St, A, Range);
   default:
     // if we're here, then we parsed an attribute, but didn't recognize it as a

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=158661&r1=158660&r2=158661&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Mon Jun 18 11:13:52 2012
@@ -2728,8 +2728,7 @@
     .create(&S.Context.Idents.get("objc_ownership"), SourceLocation(),
             /*scope*/ 0, SourceLocation(),
             &S.Context.Idents.get(attrStr), SourceLocation(),
-            /*args*/ 0, 0,
-            /*declspec*/ false, /*C++0x*/ false);
+            /*args*/ 0, 0, AttributeList::AS_GNU);
   spliceAttrIntoList(*attr, chunk.getAttrListRef());
 
   // TODO: mark whether we did this inference?

Modified: cfe/trunk/test/SemaCXX/switch-implicit-fallthrough-per-method.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/switch-implicit-fallthrough-per-method.cpp?rev=158661&r1=158660&r2=158661&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/switch-implicit-fallthrough-per-method.cpp (original)
+++ cfe/trunk/test/SemaCXX/switch-implicit-fallthrough-per-method.cpp Mon Jun 18 11:13:52 2012
@@ -37,3 +37,15 @@
   }
   return n;
 }
+
+void unscoped(int n) {
+  switch (n % 2) {
+    case 0:
+      // FIXME: This should be typo-corrected, probably.
+      [[fallthrough]];
+    case 2: // expected-warning{{unannotated fall-through}} expected-note{{clang::fallthrough}} expected-note{{break;}}
+      [[clang::fallthrough]];
+    case 1:
+      break;
+  }
+}

Modified: cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp?rev=158661&r1=158660&r2=158661&view=diff
==============================================================================
--- cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp (original)
+++ cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp Mon Jun 18 11:13:52 2012
@@ -11,6 +11,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringSwitch.h"
 #include "llvm/TableGen/Record.h"
 #include "llvm/TableGen/StringMatcher.h"
@@ -1128,6 +1129,8 @@
     if (SemaHandler || Ignored) {
       std::vector<StringRef> Spellings =
         getValueAsListOfStrings(Attr, "Spellings");
+      std::vector<StringRef> Namespaces =
+        getValueAsListOfStrings(Attr, "Namespaces");
 
       for (std::vector<StringRef>::const_iterator I = Spellings.begin(),
            E = Spellings.end(); I != E; ++I) {
@@ -1136,16 +1139,35 @@
                                                  : Spellings.front());
         StringRef Spelling = NormalizeAttrSpelling(*I);
 
+        for (std::vector<StringRef>::const_iterator NI = Namespaces.begin(),
+             NE = Namespaces.end(); NI != NE; ++NI) {
+          SmallString<64> Buf;
+          Buf += *NI;
+          Buf += "::";
+          Buf += Spelling;
+
+          if (SemaHandler)
+            Matches.push_back(
+              StringMatcher::StringPair(
+                Buf.str(),
+                "return AttributeList::AT_" + AttrName.str() + ";"));
+          else
+            Matches.push_back(
+              StringMatcher::StringPair(
+                Buf.str(),
+                "return AttributeList::IgnoredAttribute;"));
+        }
+
         if (SemaHandler)
           Matches.push_back(
             StringMatcher::StringPair(
               Spelling,
-              std::string("return AttributeList::AT_")+AttrName.str() + ";"));
+              "return AttributeList::AT_" + AttrName.str() + ";"));
         else
           Matches.push_back(
             StringMatcher::StringPair(
               Spelling,
-              std::string("return AttributeList::IgnoredAttribute;")));
+              "return AttributeList::IgnoredAttribute;"));
       }
     }
   }





More information about the cfe-commits mailing list