[cfe-commits] r38566 - in /cfe/cfe/trunk: Lex/Pragma.cpp Lex/Preprocessor.cpp include/clang/Basic/DiagnosticKinds.def include/clang/Lex/Pragma.h include/clang/Lex/Preprocessor.h

sabre at cs.uiuc.edu sabre at cs.uiuc.edu
Wed Jul 11 09:22:44 PDT 2007


Author: sabre
Date: Wed Jul 11 11:22:44 2007
New Revision: 38566

URL: http://llvm.org/viewvc/llvm-project?rev=38566&view=rev
Log:
implement the pragma handling infrastructure.  The only pragma so far is
#pragma once, and it is not completely implemented.

Added:
    cfe/cfe/trunk/Lex/Pragma.cpp   (with props)
    cfe/cfe/trunk/include/clang/Lex/Pragma.h   (with props)
Modified:
    cfe/cfe/trunk/Lex/Preprocessor.cpp
    cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def
    cfe/cfe/trunk/include/clang/Lex/Preprocessor.h

Added: cfe/cfe/trunk/Lex/Pragma.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Lex/Pragma.cpp?rev=38566&view=auto

==============================================================================
--- cfe/cfe/trunk/Lex/Pragma.cpp (added)
+++ cfe/cfe/trunk/Lex/Pragma.cpp Wed Jul 11 11:22:44 2007
@@ -0,0 +1,116 @@
+//===--- Pragma.cpp - Pragma registration and handling --------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file was developed by Chris Lattner and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the PragmaHandler and PragmaTable interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/Pragma.h"
+#include "clang/Lex/Preprocessor.h"
+using namespace llvm;
+using namespace clang;
+
+// Out-of-line destructor to provide a home for the class.
+PragmaHandler::~PragmaHandler() {
+}
+
+void PragmaNamespace::HandlePragma(Preprocessor &PP, LexerToken &Tok) {
+  // Read the 'namespace' that the directive is in, e.g. STDC.  Do not macro
+  // expand it, the user can have a STDC #define, that should not affect this.
+  PP.LexUnexpandedToken(Tok);
+  
+  // Get the handler for this token.  If there is no handler, ignore the pragma.
+  PragmaHandler *Handler = FindHandler(Tok.getIdentifierInfo(), false);
+  if (Handler == 0) return;
+  
+  // Otherwise, pass it down.
+  Handler->HandlePragma(PP, Tok);
+}
+
+
+
+#if 0
+/* Contains a registered pragma or pragma namespace.  */
+typedef void (*pragma_cb) (cpp_reader *);
+struct pragma_entry
+{
+  struct pragma_entry *next;
+  const cpp_hashnode *pragma;   /* Name and length.  */
+  bool is_nspace;
+  bool is_internal;
+  bool is_deferred;
+  bool allow_expansion;
+  union {
+    pragma_cb handler;
+    struct pragma_entry *space;
+    unsigned int ident;
+  } u;
+};
+
+
+
+/* Register a pragma NAME in namespace SPACE.  If SPACE is null, it
+goes in the global namespace.  HANDLER is the handler it will call,
+which must be non-NULL.  If ALLOW_EXPANSION is set, allow macro
+expansion while parsing pragma NAME.  This function is exported
+from libcpp. */
+void
+cpp_register_pragma (cpp_reader *pfile, const char *space, const char *name,
+                     pragma_cb handler, bool allow_expansion)
+{
+  struct pragma_entry *entry;
+  
+  if (!handler)
+  {
+    cpp_error (pfile, CPP_DL_ICE, "registering pragma with NULL handler");
+    return;
+  }
+  
+  entry = register_pragma_1 (pfile, space, name, false);
+  if (entry)
+  {
+    entry->allow_expansion = allow_expansion;
+    entry->u.handler = handler;
+  }
+}
+
+/* Similarly, but create mark the pragma for deferred processing.
+When found, a CPP_PRAGMA token will be insertted into the stream
+with IDENT in the token->u.pragma slot.  */
+void
+cpp_register_deferred_pragma (cpp_reader *pfile, const char *space,
+                              const char *name, unsigned int ident,
+                              bool allow_expansion, bool allow_name_expansion)
+{
+  struct pragma_entry *entry;
+  
+  entry = register_pragma_1 (pfile, space, name, allow_name_expansion);
+  if (entry)
+  {
+    entry->is_deferred = true;
+    entry->allow_expansion = allow_expansion;
+    entry->u.ident = ident;
+  }
+}  
+
+
+/* Register the pragmas the preprocessor itself handles.  */
+void
+_cpp_init_internal_pragmas (cpp_reader *pfile)
+{
+  /* Pragmas in the global namespace.  */
+  register_pragma_internal (pfile, 0, "once", do_pragma_once);
+  
+  /* New GCC-specific pragmas should be put in the GCC namespace.  */
+  register_pragma_internal (pfile, "GCC", "poison", do_pragma_poison);
+  register_pragma_internal (pfile, "GCC", "system_header",
+                            do_pragma_system_header);
+  register_pragma_internal (pfile, "GCC", "dependency", do_pragma_dependency);
+}
+#endif

Propchange: cfe/cfe/trunk/Lex/Pragma.cpp

------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/cfe/trunk/Lex/Pragma.cpp

------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Modified: cfe/cfe/trunk/Lex/Preprocessor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Lex/Preprocessor.cpp?rev=38566&r1=38565&r2=38566&view=diff

==============================================================================
--- cfe/cfe/trunk/Lex/Preprocessor.cpp (original)
+++ cfe/cfe/trunk/Lex/Preprocessor.cpp Wed Jul 11 11:22:44 2007
@@ -35,6 +35,7 @@
 
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/Pragma.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/FileManager.h"
 #include "clang/Basic/SourceManager.h"
@@ -62,6 +63,10 @@
 
   // There is no file-change handler yet.
   FileChangeHandler = 0;
+  
+  // Initialize the pragma handlers.
+  PragmaHandlers = new PragmaNamespace(0);
+  RegisterBuiltinPragmas();
 }
 
 Preprocessor::~Preprocessor() {
@@ -72,6 +77,9 @@
     delete IncludeStack.back().TheLexer;
     IncludeStack.pop_back();
   }
+  
+  // Release pragma information.
+  delete PragmaHandlers;
 }
 
 /// getFileInfo - Return the PerFileInfo structure for the specified
@@ -837,11 +845,11 @@
     switch (Result.getIdentifierInfo()->getNameLength()) {
     case 4:
       if (Directive[0] == 'l' && !strcmp(Directive, "line"))
-        ;
+        ;  // FIXME: implement #line
       if (Directive[0] == 'e' && !strcmp(Directive, "elif"))
         return HandleElifDirective(Result);
       if (Directive[0] == 's' && !strcmp(Directive, "sccs")) {
-        isExtension = true;
+        isExtension = true;  // FIXME: implement #sccs
         // SCCS is the same as #ident.
       }
       break;
@@ -855,7 +863,7 @@
       if (Directive[0] == 'e' && !strcmp(Directive, "error"))
         return HandleUserDiagnosticDirective(Result, false);
       if (Directive[0] == 'i' && !strcmp(Directive, "ident"))
-        isExtension = true;
+        isExtension = true;  // FIXME: implement #ident
       break;
     case 6:
       if (Directive[0] == 'd' && !strcmp(Directive, "define"))
@@ -864,20 +872,10 @@
         return HandleIfdefDirective(Result, true);
       if (Directive[0] == 'i' && !strcmp(Directive, "import"))
         return HandleImportDirective(Result);
-      if (Directive[0] == 'p' && !strcmp(Directive, "pragma")) {
-        // FIXME: implement #pragma
-        ++NumPragma;
-#if 1
-        // Read the rest of the PP line.
-        do {
-          Lex(Result);
-        } while (Result.getKind() != tok::eom);
-        
-        return;
-#endif
-      } else if (Directive[0] == 'a' && !strcmp(Directive, "assert")) {
-        isExtension = true;
-      }
+      if (Directive[0] == 'p' && !strcmp(Directive, "pragma"))
+        return HandlePragmaDirective(Result);
+      if (Directive[0] == 'a' && !strcmp(Directive, "assert"))
+        isExtension = true;  // FIXME: implement #assert
       break;
     case 7:
       if (Directive[0] == 'i' && !strcmp(Directive, "include"))
@@ -889,7 +887,7 @@
       break;
     case 8:
       if (Directive[0] == 'u' && !strcmp(Directive, "unassert")) {
-        isExtension = true;
+        isExtension = true;  // FIXME: implement #unassert
       }
       break;
     case 12:
@@ -924,6 +922,10 @@
   return Diag(Result, DiagID, Message);
 }
 
+//===----------------------------------------------------------------------===//
+// Preprocessor Include Directive Handling.
+//===----------------------------------------------------------------------===//
+
 /// HandleIncludeDirective - The "#include" tokens have just been read, read the
 /// file to be included from the lexer, then include it!  This is a common
 /// routine with functionality shared between #include, #include_next and
@@ -1035,6 +1037,10 @@
   return HandleIncludeDirective(ImportTok, 0, true);
 }
 
+//===----------------------------------------------------------------------===//
+// Preprocessor Macro Directive Handling.
+//===----------------------------------------------------------------------===//
+
 /// HandleDefineDirective - Implements #define.  This consumes the entire macro
 /// line then lets the caller lex the next real token.
 ///
@@ -1128,6 +1134,10 @@
 }
 
 
+//===----------------------------------------------------------------------===//
+// Preprocessor Conditional Directive Handling.
+//===----------------------------------------------------------------------===//
+
 /// HandleIfdefDirective - Implements the #ifdef/#ifndef directive.  isIfndef is
 /// true when this is a #ifndef directive.
 ///
@@ -1233,3 +1243,84 @@
   return SkipExcludedConditionalBlock(CI.IfLoc, /*Foundnonskip*/true,
                                       /*FoundElse*/CI.FoundElse);
 }
+
+
+//===----------------------------------------------------------------------===//
+// Preprocessor Pragma Directive Handling.
+//===----------------------------------------------------------------------===//
+
+/// HandlePragmaDirective - The "#pragma" directive has been parsed with
+/// PragmaTok containing the "pragma" identifier.  Lex the rest of the pragma,
+/// passing it to the registered pragma handlers.
+void Preprocessor::HandlePragmaDirective(LexerToken &PragmaTok) {
+  ++NumPragma;
+  
+  // Invoke the first level of pragma handlers which reads the namespace id.
+  LexerToken Tok;
+  PragmaHandlers->HandlePragma(*this, Tok);
+  
+  // If the pragma handler didn't read the rest of the line, consume it now.
+  if (CurLexer->ParsingPreprocessorDirective) {
+    do {
+      LexUnexpandedToken(Tok);
+    } while (Tok.getKind() != tok::eom);
+  }
+}
+
+/// HandlePragmaOnce - Handle #pragma once.  OnceTok is the 'once'.
+void Preprocessor::HandlePragmaOnce(LexerToken &OnceTok) {
+  if (IncludeStack.empty()) {
+    Diag(OnceTok, diag::pp_pragma_once_in_main_file);
+    return;
+  }
+}
+
+
+/// AddPragmaHandler - Add the specified pragma handler to the preprocessor.
+/// If 'Namespace' is non-null, then it is a token required to exist on the
+/// pragma line before the pragma string starts, e.g. "STDC" or "GCC".
+void Preprocessor::AddPragmaHandler(const char *Namespace, 
+                                    PragmaHandler *Handler) {
+  PragmaNamespace *InsertNS = PragmaHandlers;
+  
+  // If this is specified to be in a namespace, step down into it.
+  if (Namespace) {
+    IdentifierTokenInfo *NSID = getIdentifierInfo(Namespace);
+    
+    // If there is already a pragma handler with the name of this namespace,
+    // we either have an error (directive with the same name as a namespace) or
+    // we already have the namespace to insert into.
+    if (PragmaHandler *Existing = PragmaHandlers->FindHandler(NSID)) {
+      InsertNS = Existing->getIfNamespace();
+      assert(InsertNS != 0 && "Cannot have a pragma namespace and pragma"
+             " handler with the same name!");
+    } else {
+      // Otherwise, this namespace doesn't exist yet, create and insert the
+      // handler for it.
+      InsertNS = new PragmaNamespace(NSID);
+      PragmaHandlers->AddPragma(InsertNS);
+    }
+  }
+  
+  // Check to make sure we don't already have a pragma for this identifier.
+  assert(!InsertNS->FindHandler(Handler->getName()) &&
+         "Pragma handler already exists for this identifier!");
+  InsertNS->AddPragma(Handler);
+}
+
+class PragmaOnceHandler : public PragmaHandler {
+public:
+  PragmaOnceHandler(const IdentifierTokenInfo *OnceID) : PragmaHandler(OnceID){}
+  virtual void HandlePragma(Preprocessor &PP, LexerToken &OnceTok) {
+    PP.CheckEndOfDirective("#pragma once");
+    PP.HandlePragmaOnce(OnceTok);
+  }
+};
+
+
+/// RegisterBuiltinPragmas - Install the standard preprocessor pragmas:
+/// #pragma GCC poison/system_header/dependency and #pragma once.
+void Preprocessor::RegisterBuiltinPragmas() {
+  AddPragmaHandler(0, new PragmaOnceHandler(getIdentifierInfo("once")));
+  
+}

Modified: cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=38566&r1=38565&r2=38566&view=diff

==============================================================================
--- cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def Wed Jul 11 11:22:44 2007
@@ -86,6 +86,8 @@
      "#include_next with absolute path")
 DIAG(ext_c99_whitespace_required_after_macro_name, WARNING,
      "ISO C99 requires whitespace after the macro name")
+DIAG(pp_pragma_once_in_main_file, WARNING,
+     "#pragma once in main file")
 
 DIAG(ext_pp_import_directive, EXTENSION,
      "#import is a language extension")

Added: cfe/cfe/trunk/include/clang/Lex/Pragma.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Lex/Pragma.h?rev=38566&view=auto

==============================================================================
--- cfe/cfe/trunk/include/clang/Lex/Pragma.h (added)
+++ cfe/cfe/trunk/include/clang/Lex/Pragma.h Wed Jul 11 11:22:44 2007
@@ -0,0 +1,94 @@
+//===--- Pragma.h - Pragma registration and handling ------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file was developed by Chris Lattner and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the PragmaHandler and PragmaTable interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_PRAGMA_H
+#define LLVM_CLANG_PRAGMA_H
+
+#include <cassert>
+#include <vector>
+
+namespace llvm {
+namespace clang {
+  class Preprocessor;
+  class LexerToken;
+  class IdentifierTokenInfo;
+  class PragmaNamespace;
+
+/// PragmaHandler - Instances of this interface defined to handle the various
+/// pragmas that the language front-end uses.  Each handler optionally has a
+/// name (e.g. "pack") and the HandlePragma method is invoked when a pragma with
+/// that identifier is found.  If a handler does not match any of the declared
+/// pragmas the handler with a null identifier is invoked, if it exists.
+///
+/// Note that the PragmaNamespace class can be used to subdivide pragmas, e.g.
+/// we treat "#pragma STDC" and "#pragma GCC" as namespaces that contain other
+/// pragmas.
+class PragmaHandler {
+  const IdentifierTokenInfo *Name;
+public:
+  PragmaHandler(const IdentifierTokenInfo *name) : Name(name) {}
+  virtual ~PragmaHandler();
+  
+  const IdentifierTokenInfo *getName() const { return Name; }
+  virtual void HandlePragma(Preprocessor &PP, LexerToken &FirstToken) = 0;
+  
+  /// getIfNamespace - If this is a namespace, return it.  This is equivalent to
+  /// using a dynamic_cast, but doesn't require RTTI.
+  virtual PragmaNamespace *getIfNamespace() { return 0; }
+};
+
+
+class PragmaNamespace : public PragmaHandler {
+  /// Handlers - This is the list of handlers in this namespace.
+  ///
+  std::vector<PragmaHandler*> Handlers;
+public:
+  PragmaNamespace(const IdentifierTokenInfo *Name) : PragmaHandler(Name) {}
+  ~PragmaNamespace() {
+    for (unsigned i = 0, e = Handlers.size(); i != e; ++i)
+      delete Handlers[i];
+  }
+
+  /// FindHandler - Check to see if there is already a handler for the
+  /// specified name.  If not, return the handler for the null identifier if it
+  /// exists, otherwise return null.  If IgnoreNull is true (the default) then
+  /// the null handler isn't returned on failure to match.
+  PragmaHandler *FindHandler(const IdentifierTokenInfo *Name,
+                             bool IgnoreNull = true) const {
+    PragmaHandler *NullHandler = 0;
+    for (unsigned i = 0, e = Handlers.size(); i != e; ++i) {
+      if (Handlers[i]->getName() == Name) 
+        return Handlers[i];
+      
+      if (Handlers[i]->getName() == 0)
+        NullHandler = Handlers[i];
+    }
+    return IgnoreNull ? 0 : NullHandler;
+  }
+  
+  /// AddPragma - Add a pragma to this namespace.
+  ///
+  void AddPragma(PragmaHandler *Handler) {
+    Handlers.push_back(Handler);
+  }
+
+  virtual void HandlePragma(Preprocessor &PP, LexerToken &FirstToken);
+  
+  virtual PragmaNamespace *getIfNamespace() { return this; }
+};
+
+
+}  // end namespace clang
+}  // end namespace llvm
+
+#endif

Propchange: cfe/cfe/trunk/include/clang/Lex/Pragma.h

------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/cfe/trunk/include/clang/Lex/Pragma.h

------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Modified: cfe/cfe/trunk/include/clang/Lex/Preprocessor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Lex/Preprocessor.h?rev=38566&r1=38565&r2=38566&view=diff

==============================================================================
--- cfe/cfe/trunk/include/clang/Lex/Preprocessor.h (original)
+++ cfe/cfe/trunk/include/clang/Lex/Preprocessor.h Wed Jul 11 11:22:44 2007
@@ -28,6 +28,8 @@
 class FileManager;
 class DirectoryEntry;
 class FileEntry;
+class PragmaNamespace;
+class PragmaHandler;
 
 /// DirectoryLookup - This class is used to specify the search order for
 /// directories in #include directives.
@@ -109,6 +111,10 @@
   /// the program, including program keywords.
   IdentifierTable IdentifierInfo;
   
+  /// PragmaHandlers - This tracks all of the pragmas that the client registered
+  /// with this preprocessor.
+  PragmaNamespace *PragmaHandlers;
+  
   /// CurLexer - This is the current top of the stack that we're lexing from if
   /// not expanding a macro.  One of CurLexer and CurMacroExpander must be null.
   Lexer *CurLexer;
@@ -221,6 +227,9 @@
     if (SkippingContents) return 0;
     return &IdentifierInfo.get(NameStart, NameEnd);
   }
+  IdentifierTokenInfo *getIdentifierInfo(const char *NameStr) {
+    return getIdentifierInfo(NameStr, NameStr+strlen(NameStr));
+  }
   
   /// AddKeyword - This method is used to associate a token ID with specific
   /// identifiers because they are language keywords.  This causes the lexer to
@@ -246,6 +255,12 @@
   /// AddKeywords - Add all keywords to the symbol table.
   ///
   void AddKeywords();
+  
+  
+  /// AddPragmaHandler - Add the specified pragma handler to the preprocessor.
+  /// If 'Namespace' is non-null, then it is a token required to exist on the
+  /// pragma line before the pragma string starts, e.g. "STDC" or "GCC".
+  void AddPragmaHandler(const char *Namespace, PragmaHandler *Handler);
 
   /// LookupFile - Given a "foo" or <foo> reference, look up the indicated file,
   /// return null on failure.  isAngled indicates whether the file reference is
@@ -339,6 +354,9 @@
   /// read is the correct one.
   void HandleDirective(LexerToken &Result);
 
+  /// CheckEndOfDirective - Ensure that the next token is a tok::eom token.  If
+  /// not, emit a diagnostic and consume up until the eom.
+  void CheckEndOfDirective(const char *Directive);
 private:
   /// getFileInfo - Return the PerFileInfo structure for the specified
   /// FileEntry.
@@ -353,10 +371,6 @@
   /// and discards the rest of the macro line if the macro name is invalid.
   void ReadMacroName(LexerToken &MacroNameTok);
   
-  /// CheckEndOfDirective - Ensure that the next token is a tok::eom token.  If
-  /// not, emit a diagnostic and consume up until the eom.
-  void CheckEndOfDirective(const char *Directive);
-  
   /// SkipExcludedConditionalBlock - We just read a #if or related directive and
   /// decided that the subsequent tokens are in the #if'd out portion of the
   /// file.  Lex the rest of the file, until we see an #endif.  If
@@ -378,6 +392,10 @@
   bool EvaluateDirectiveSubExpr(int &LHS, unsigned MinPrec,
                                 LexerToken &PeekTok);
   
+  /// RegisterBuiltinPragmas - Install the standard preprocessor pragmas:
+  /// #pragma GCC poison/system_header/dependency and #pragma once.
+  void RegisterBuiltinPragmas();
+  
   //===--------------------------------------------------------------------===//
   /// Handle*Directive - implement the various preprocessor directives.  These
   /// should side-effect the current preprocessor object so that the next call
@@ -386,22 +404,29 @@
   void HandleUserDiagnosticDirective(LexerToken &Result, bool isWarning);
   
   // File inclusion.
-  void HandleIncludeDirective(LexerToken &Result,
+  void HandleIncludeDirective(LexerToken &Tok,
                               const DirectoryLookup *LookupFrom = 0,
                               bool isImport = false);
-  void HandleIncludeNextDirective(LexerToken &Result);
-  void HandleImportDirective(LexerToken &Result);
+  void HandleIncludeNextDirective(LexerToken &Tok);
+  void HandleImportDirective(LexerToken &Tok);
   
   // Macro handling.
-  void HandleDefineDirective(LexerToken &Result);
-  void HandleUndefDirective(LexerToken &Result);
+  void HandleDefineDirective(LexerToken &Tok);
+  void HandleUndefDirective(LexerToken &Tok);
+  // HandleAssertDirective(LexerToken &Tok);
+  // HandleUnassertDirective(LexerToken &Tok);
   
   // Conditional Inclusion.
-  void HandleIfdefDirective(LexerToken &Result, bool isIfndef);
-  void HandleIfDirective(LexerToken &Result);
-  void HandleEndifDirective(LexerToken &Result);
-  void HandleElseDirective(LexerToken &Result);
-  void HandleElifDirective(LexerToken &Result);
+  void HandleIfdefDirective(LexerToken &Tok, bool isIfndef);
+  void HandleIfDirective(LexerToken &Tok);
+  void HandleEndifDirective(LexerToken &Tok);
+  void HandleElseDirective(LexerToken &Tok);
+  void HandleElifDirective(LexerToken &Tok);
+  
+  // Pragmas.
+  void HandlePragmaDirective(LexerToken &Result);
+public:
+  void HandlePragmaOnce(LexerToken &OnceTok);
 };
 
 }  // end namespace clang





More information about the cfe-commits mailing list