Index: clang/include/clang/Basic/DiagnosticLexKinds.td
===================================================================
--- clang.orig/include/clang/Basic/DiagnosticLexKinds.td	2011-12-08 19:17:59.599899300 +1000
+++ clang/include/clang/Basic/DiagnosticLexKinds.td	2011-12-08 19:19:22.050784300 +1000
@@ -232,6 +232,14 @@
   "expected comma in macro parameter list">;
 def err_pp_duplicate_name_in_arg_list : Error<
   "duplicate macro parameter name %0">;
+def err_pp_predicate_not_identifier : Error<"assertion predicates must be identifiers">;
+def err_pp_missing_assert_predicate : Error<"assertion predicatee missing">;
+def err_pp_missing_lparen_after_assertion_predicate : Error<
+  "expected '(' after pre-processor assertion predicate">;
+def err_pp_missing_rparen_after_assertion_value : Error<
+  "expected closing ')' at end of asserted value; values cannot contain parentheses">;
+def err_pp_extra_tok_after_assertion : Error<
+  "No additional tokens may follow a pre-processor %0 directive">;
 def err_pp_stringize_not_parameter : Error<
   "'#' is not followed by a macro parameter">;
 def err_pp_malformed_ident : Error<"invalid #ident directive">;
@@ -320,6 +328,7 @@
 
 def err_pragma_comment_unknown_kind : Error<"unknown kind of pragma comment">;
 def err_defined_macro_name : Error<"'defined' cannot be used as a macro name">;
+def err_assert_predicate_name : Error<"'assert' cannote be used as an assertion predicate">;
 def err_paste_at_start : Error<
   "'##' cannot appear at start of macro expansion">;
 def err_paste_at_end : Error<"'##' cannot appear at end of macro expansion">;
@@ -338,6 +347,8 @@
   InGroup<DiagGroup<"invalid-token-paste">>;
 def err_pp_operator_used_as_macro_name : Error<
   "C++ operator '%0' cannot be used as a macro name">;
+def err_pp_operator_used_as_assert_predicate : Error<
+  "C++ operator '%0' cannot be used as an assertion predicate">;
 def err_pp_illegal_floating_literal : Error<
   "floating point literal in preprocessor expression">;
 def err_pp_line_requires_integer : Error<
Index: clang/include/clang/Lex/Preprocessor.h
===================================================================
--- clang.orig/include/clang/Lex/Preprocessor.h	2011-12-08 19:17:59.000000000 +1000
+++ clang/include/clang/Lex/Preprocessor.h	2011-12-12 16:05:56.191899300 +1000
@@ -15,6 +15,7 @@
 #define LLVM_CLANG_LEX_PREPROCESSOR_H
 
 #include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/AssertionInfo.h"
 #include "clang/Lex/Lexer.h"
 #include "clang/Lex/PTHLexer.h"
 #include "clang/Lex/PPCallbacks.h"
@@ -24,6 +25,7 @@
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/IdentifierTable.h"
 #include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/UsuallyTinyPtrVector.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/IntrusiveRefCntPtr.h"
 #include "llvm/ADT/SmallPtrSet.h"
@@ -240,6 +242,16 @@
   /// to the actual definition of the macro.
   llvm::DenseMap<IdentifierInfo*, MacroInfo*> Macros;
 
+  /// Assertions - For each IdentifierInfo that has appeared as an asserted
+  /// predicate, we store the values for which it was asserted
+  llvm::DenseMap<IdentifierInfo*, UsuallyTinyPtrVector<AssertionInfo> > AssertedValues;
+
+  enum AssertionPredicateKind {
+    APK_Unknown,
+    APK_Assert,
+    APK_Unassert
+  };
+
   /// \brief Macros that we want to warn because they are not used at the end
   /// of the translation unit; we store just their SourceLocations instead
   /// something like MacroInfo*. The benefit of this is that when we are
@@ -326,6 +338,20 @@
 
   MacroInfo *getInfoForMacro(IdentifierInfo *II) const;
 
+  struct AssertionInfoChain {
+    AssertionInfo AI;
+    AssertionInfoChain *Next;
+    AssertionInfoChain *Prev;
+  };
+
+  /// AIChainHead - AssertionInfo objects are managed as a chain for easy
+  /// disposal. This is the head of that list.
+  AssertionInfoChain *AIChainHead;
+
+  /// AICache - A "freelist" of AssertionInfo objects that can be resused for
+  /// quick allocation.
+  AssertionInfoChain *AICache;
+
 public:
   Preprocessor(DiagnosticsEngine &diags, LangOptions &opts,
                const TargetInfo *target,
@@ -440,6 +466,35 @@
   macro_iterator macro_begin(bool IncludeExternalMacros = true) const;
   macro_iterator macro_end(bool IncludeExternalMacros = true) const;
 
+  /// addAssertionValue - assert the specified identifier to the
+  /// set of asserted values for the given assertion key
+  void addAssertionValue(IdentifierInfo *II, AssertionInfo *AI);
+
+  /// isAsserted - test if the specified identifier has been asserted as a
+  /// value of the given assertion key returns true iff it has
+  bool isAsserted(IdentifierInfo *II, AssertionInfo *AI);
+
+  /// removeAssertionValue - remove the specified identifier from the set of
+  /// asserted values for the given assertion key
+  void removeAssertionValue(IdentifierInfo *II, AssertionInfo *AI);
+
+  /// removeAssertion - remove the specified assertion and all of its asserted
+  /// values
+  void removeAssertion(IdentifierInfo *II);
+
+  /// assertion_iterator/assertion_begin/assertion_end - This allows you to
+  /// walk the current state of the assertions table. This visits every
+  /// currently asserted predicate
+  typedef llvm::DenseMap<IdentifierInfo*,
+      UsuallyTinyPtrVector<AssertionInfo> >::iterator assertion_iterator;
+  assertion_iterator assertion_begin();
+  assertion_iterator assertion_end();
+
+  /// assertion_value_iterator - A helpful type for traversing the values
+  /// asserted for a given predicate
+  typedef UsuallyTinyPtrVector<AssertionInfo>::iterator
+                                                      assertion_value_iterator;
+
   const std::string &getPredefines() const { return Predefines; }
   /// setPredefines - Set the predefines for this Preprocessor.  These
   /// predefines are automatically injected when parsing the main file.
@@ -985,6 +1040,10 @@
   unsigned getCounterValue() const { return CounterValue; }
   void setCounterValue(unsigned V) { CounterValue = V; }
 
+  /// allocateAssertionInfo - Allocate a new AssertionInfo object with the
+  /// provided SourceLocation.
+  AssertionInfo *allocateAssertionInfo(SourceLocation L);
+
   /// AllocateMacroInfo - Allocate a new MacroInfo object with the provide
   ///  SourceLocation.
   MacroInfo *AllocateMacroInfo(SourceLocation L);
@@ -1077,6 +1136,30 @@
   /// parsing the arg list.
   bool ReadMacroDefinitionArgList(MacroInfo *MI);
 
+  /// allocateAssertionInfo - Allocate a new AssertionInfo object, possibly
+  /// recycling previously unallocated AssertionInfo objects
+  AssertionInfo *allocateAssertionInfo();
+
+public:
+  /// releaseAssertionInfo - Release the specified AssertionInfo. This memory
+  /// will be reused for allocating new AssertionInfo objects
+  void releaseAssertionInfo(AssertionInfo *AI);
+
+private:
+  /// readAssertionPredicate - Lex and validate an assertion name, which occurs
+  /// an #assert or #unassert. This emits a diagnostic, sets the token kind to
+  /// eod, and discards the rest of the assertion line if the predicate is
+  /// invalid. Returns false iff a predicate is successfully lexed.
+  bool readAssertionPredicate(Token &AssertionPredicateTok,
+                                                   AssertionPredicateKind APK);
+
+  /// readAssertionValue - Lex and validate an assertion value, which occurs in
+  /// parentheses after an #assert or #unassert and its predicate. This
+  /// function handles lexing the open and close parens and validates them.
+  /// This emits a diagnostic, sets the token kind to eod, and discards the
+  /// rest of the assertioin line if the predicate is invalid.
+  AssertionInfo *readAssertionValue(Token &Tok, SourceLocation PredicateLoc);
+
   /// 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
@@ -1208,6 +1291,10 @@
   void HandleDefineDirective(Token &Tok);
   void HandleUndefDirective(Token &Tok);
 
+  // Assetion handling.
+  void handleAssertDirective(Token &Tok);
+  void handleUnassertDirective(Token &Tok);
+
   // Conditional Inclusion.
   void HandleIfdefDirective(Token &Tok, bool isIfndef,
                             bool ReadAnyTokensBeforeDirective);
Index: clang/lib/Lex/CMakeLists.txt
===================================================================
--- clang.orig/lib/Lex/CMakeLists.txt	2011-12-08 19:17:59.615899300 +1000
+++ clang/lib/Lex/CMakeLists.txt	2011-12-08 19:19:22.105291200 +1000
@@ -11,6 +11,8 @@
   LiteralSupport.cpp
   MacroArgs.cpp
   MacroInfo.cpp
+  AssertionInfo.cpp
+  PPAssertionHandler.cpp
   ModuleMap.cpp
   PPCaching.cpp
   PPDirectives.cpp
Index: clang/lib/Lex/PPDirectives.cpp
===================================================================
--- clang.orig/lib/Lex/PPDirectives.cpp	2011-12-08 19:17:59.620899300 +1000
+++ clang/lib/Lex/PPDirectives.cpp	2011-12-12 16:05:56.229899300 +1000
@@ -81,6 +81,53 @@
   MI->Destroy();
 }
 
+AssertionInfo *Preprocessor::allocateAssertionInfo() {
+  AssertionInfoChain *AIChain;
+
+  if (AICache) {
+    AIChain = AICache;
+    AICache = AICache->Next;
+  } else {
+    AIChain = BP.Allocate<AssertionInfoChain>();
+  }
+
+  AIChain->Next = AIChainHead;
+  AIChain->Prev = 0;
+  if (AIChainHead)
+    AIChainHead->Prev = AIChain;
+  AIChainHead = AIChain;
+
+  return &(AIChain->AI);
+}
+
+AssertionInfo *Preprocessor::allocateAssertionInfo(SourceLocation L) {
+  AssertionInfo *AI = allocateAssertionInfo();
+  new (AI) AssertionInfo(L);
+  return AI;
+}
+
+/// ReleaseMacroInfo - Release the specified AssertionInfo. This memory will be
+/// reused for allocating new AssertionInfo objects.
+void Preprocessor::releaseAssertionInfo(AssertionInfo *AI) {
+  AssertionInfoChain *AIChain = (AssertionInfoChain*)AI;
+  if (AssertionInfoChain *Prev = AIChain->Prev) {
+    AssertionInfoChain *Next = AIChain->Next;
+    Prev->Next = Next;
+    if (Next) {
+      Next->Prev = Prev;
+    }
+  } else {
+    assert(AIChainHead == AIChain);
+    AIChainHead = AIChain->Next;
+    if (AIChainHead)
+      AIChainHead->Prev = 0;
+  }
+  AIChain->Next = AICache;
+  AICache = AIChain;
+
+  AI->destroy();
+}
+
 /// DiscardUntilEndOfDirective - Read and discard all tokens remaining on the
 /// current line until the tok::eod token is found.
 void Preprocessor::DiscardUntilEndOfDirective() {
@@ -91,6 +138,55 @@
   } while (Tmp.isNot(tok::eod));
 }
 
+/// readAssertionPredicate - Lex and validate an assertion predicate, which
+/// occurs after an #assert or #unassert. This sets the token kind to eod and
+/// discards the rest of the line if the assert is invalid.
+/// isAssertUnassert is 1 if this is due to an #assert, 2 if #unassert
+/// directive, 0 if it is something else.
+/// Returns false iff a predicate is successfully lexed.
+bool Preprocessor::readAssertionPredicate(Token &AssertionPredTok,
+    AssertionPredicateKind APK) {
+  //Read the token, don't allow macro expansion on it
+  LexUnexpandedToken(AssertionPredTok);
+
+  // Missing assertion predicate?
+  if (AssertionPredTok.is(tok::eod)) {
+    Diag(AssertionPredTok, diag::err_pp_missing_assert_predicate);
+    return true;
+  }
+
+  if (IdentifierInfo *II = AssertionPredTok.getIdentifierInfo()) {
+    if ((APK == APK_Assert || APK == APK_Unassert) &&
+        II->getPPKeywordID() == tok::pp_assert) {
+      // Error if using assert as a predicate since using it would require
+      // #assert
+      return Diag(AssertionPredTok, diag::err_assert_predicate_name);
+    }
+    return false;
+  }
+
+  // diagnose non-identifiers
+  bool Invalid = false;
+  std::string Spelling = getSpelling(AssertionPredTok, &Invalid);
+  if (Invalid) {
+    return true;
+  }
+
+  const IdentifierInfo &Info = Identifiers.get(Spelling);
+  if (Info.isCPlusPlusOperatorKeyword()) {
+    Diag(AssertionPredTok, diag::err_pp_operator_used_as_assert_predicate)
+      << Spelling;
+  } else {
+    Diag(AssertionPredTok, diag::err_pp_predicate_not_identifier);
+  }
+
+  // Invalid name, read and disacard the rest of the line. Then set the token
+  // kind to tok::eod
+  AssertionPredTok.setKind(tok::eod);
+  DiscardUntilEndOfDirective();
+  return true;
+}
+
 /// ReadMacroName - Lex and validate a macro name, which occurs after a
 /// #define or #undef.  This sets the token kind to eod and discards the rest
 /// of the macro line if the macro name is invalid.  isDefineUndef is 1 if
@@ -659,11 +755,9 @@
     case tok::pp_sccs:
       return HandleIdentSCCSDirective(Result);
     case tok::pp_assert:
-      //isExtension = true;  // FIXME: implement #assert
-      break;
+      return handleAssertDirective(Result);
     case tok::pp_unassert:
-      //isExtension = true;  // FIXME: implement #unassert
-      break;
+      return handleUnassertDirective(Result);
         
     case tok::pp___export_macro__:
       return HandleMacroExportDirective(Result);
@@ -1739,6 +1833,102 @@
   setMacroInfo(MacroNameTok.getIdentifierInfo(), 0);
 }
 
+//===----------------------------------------------------------------------===//
+// Preprocessor Assertion Directive Handling.
+//===----------------------------------------------------------------------===//
+void Preprocessor::handleAssertDirective(Token &DTok) {
+  Token AssertionPredicateTok;
+
+  // check to see if an error has occured and
+  // an appropriate diagnostic has already been generated
+  if (readAssertionPredicate(AssertionPredicateTok, APK_Assert)) {
+    return;
+  }
+
+  Token Tok;
+  LexUnexpandedToken(Tok);
+  AssertionInfo *AI = readAssertionValue(Tok, AssertionPredicateTok.getLocation());
+
+  // add to AI
+  if (AI) {
+    addAssertionValue(AssertionPredicateTok.getIdentifierInfo(), AI);
+  }
+
+  // check there is nothing after the closing ), if we have anything release
+  // the Assertioninfo and idscard the rest of the directive
+  LexUnexpandedToken(Tok);
+  if (!Tok.is(tok::eod)) {
+    Diag(Tok, diag::err_pp_extra_tok_after_assertion) << "assert";
+    DiscardUntilEndOfDirective();
+  }
+}
+
+void Preprocessor::handleUnassertDirective(Token &DTok) {
+  Token AssertionPredicateTok;
+
+  // check to see if an error has occured and
+  // an appropriate diagnostic has already been generated
+  if (readAssertionPredicate(AssertionPredicateTok, APK_Unassert)) {
+    return;
+  }
+
+  IdentifierInfo *II = AssertionPredicateTok.getIdentifierInfo();
+
+  Token Tok;
+  LexUnexpandedToken(Tok);
+
+  if (Tok.is(tok::eod)) {
+    removeAssertion(II);
+  } else {
+    AssertionInfo *AI = readAssertionValue(Tok,
+                                          AssertionPredicateTok.getLocation());
+
+    if (AI) {
+      removeAssertionValue(II, AI);
+      releaseAssertionInfo(AI);
+    }
+    LexUnexpandedToken(Tok);
+  }
+
+  // check there is nothing after the closing ), if we have anything release
+  // the Assertioninfo and idscard the rest of the directive
+  if (!Tok.is(tok::eod)) {
+    Diag(Tok, diag::err_pp_extra_tok_after_assertion) << "unassert";
+    DiscardUntilEndOfDirective();
+  }
+}
+
+AssertionInfo *Preprocessor::readAssertionValue(Token &Tok,
+                                                 SourceLocation PredicateLoc) {
+  if (Tok.isNot(tok::l_paren)) {
+    Diag(Tok, diag::err_pp_missing_lparen_after_assertion_predicate);
+    DiscardUntilEndOfDirective();
+    return NULL;
+  }
+
+  AssertionInfo *AI = allocateAssertionInfo(PredicateLoc);
+
+  // NOTE: parentheses in assertions do NOT nest - see
+  // http://gcc.gnu.org/onlinedocs/gcc-2.95.3/cpp_1.html#SEC37 para 3
+  while (true) {
+    LexUnexpandedToken(Tok);
+    if (Tok.is(tok::r_paren) || Tok.is(tok::eod)) {
+      break;
+    }
+    AI->AddToken(Tok);
+  }
+
+  // check for the closing ), if we don't have it release the AssetionInfo and
+  // discard the rest of the directive
+  if (!Tok.is(tok::r_paren)) {
+    Diag(Tok, diag::err_pp_missing_rparen_after_assertion_value);
+    releaseAssertionInfo(AI);
+    DiscardUntilEndOfDirective();
+    return NULL;
+  }
+
+  return AI;
+}
 
 //===----------------------------------------------------------------------===//
 // Preprocessor Conditional Directive Handling.
Index: clang/lib/Lex/PPExpressions.cpp
===================================================================
--- clang.orig/lib/Lex/PPExpressions.cpp	2011-12-08 19:17:59.624899300 +1000
+++ clang/lib/Lex/PPExpressions.cpp	2011-12-08 19:19:22.125293700 +1000
@@ -11,12 +11,9 @@
 // which parses and evaluates integer constant expressions for #if directives.
 //
 //===----------------------------------------------------------------------===//
-//
-// FIXME: implement testing for #assert's.
-//
-//===----------------------------------------------------------------------===//
 
 #include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/AssertionInfo.h"
 #include "clang/Lex/MacroInfo.h"
 #include "clang/Lex/LiteralSupport.h"
 #include "clang/Lex/CodeCompletionHandler.h"
@@ -381,7 +378,47 @@
     return false;
   }
 
-  // FIXME: Handle #assert
+  case tok::hash: {
+    Token PredicateTok;
+    PP.LexUnexpandedToken(PredicateTok);
+
+    AssertionInfo *AI = PP.allocateAssertionInfo(PredicateTok.getLocation());
+    PP.LexUnexpandedToken(PeekTok);
+    if (PeekTok.isNot(tok::l_paren) || PredicateTok.getIdentifierInfo() == 0) {
+      PP.Diag(PredicateTok, diag::err_pp_expr_bad_token_start_expr);
+      PP.releaseAssertionInfo(AI);
+      AI = 0;
+      return true;
+    }
+
+    // NOTE: parentheses in assertions do NOT nest - see
+    // http://gcc.gnu.org/onlinedocs/gcc-2.95.3/cpp_1.html#SEC37 para 3
+    while (true) {
+      PP.LexUnexpandedToken(PeekTok);
+      if (PeekTok.is(tok::r_paren) || PeekTok.is(tok::eod)) {
+        break;
+      }
+      AI->AddToken(PeekTok);
+    }
+
+    // check for the closing ), if we don't have it release the AssertionInfo
+    // and discard the rest of the directive
+    if (!PeekTok.is(tok::r_paren)) {
+      PP.Diag(PredicateTok, diag::err_pp_expr_bad_token_start_expr);
+      PP.releaseAssertionInfo(AI);
+      AI = 0;
+      return true;
+    }
+    PP.LexUnexpandedToken(PeekTok);
+
+    IdentifierInfo *II = PredicateTok.getIdentifierInfo();
+
+    Result.Val = PP.isAsserted(II, AI) ? 1 : 0;
+    PP.releaseAssertionInfo(AI);
+    AI = 0;
+    return false;
+  }
+
   }
 }
 
Index: clang/include/clang/Lex/AssertionInfo.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ clang/include/clang/Lex/AssertionInfo.h	2011-12-12 16:05:56.162899300 +1000
@@ -0,0 +1,65 @@
+//===--- AssertionInfo.h - C Language Family Preprocessor --------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file defines the AssertionInfo structure used to store information
+//  about GNU-style pre-processor assertions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ASSERTIONINFO_H
+#define LLVM_CLANG_ASSERTIONINFO_H
+
+#include "clang/Lex/Token.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Allocator.h"
+#include <vector>
+
+namespace clang {
+  class Preprocessor;
+
+  /// AssertionInfo - Each identifier that is used as a predicate in an
+  /// assertion statement has one or more instances of this class associated
+  /// with it to store the values pattern(s) asserted for it
+  class AssertionInfo {
+    /// AssertLoc - The SourceLocation of the assertion
+    SourceLocation AssertLoc;
+
+    /// ValueTokens - The tokens that make up the assertion
+    llvm::SmallVector<Token, 8> ValueTokens;
+
+    ~AssertionInfo() { }
+  public:
+    AssertionInfo(SourceLocation Loc) : AssertLoc(Loc) { }
+
+    void destroy() {
+      ValueTokens.clear();
+      this->~AssertionInfo();
+    }
+
+    /// AddToken - Adds a single token to the assertion's token sequence
+    void AddToken(Token &t) {
+      ValueTokens.push_back(t);
+    }
+
+    SourceLocation getAssertionLoc() const { return AssertLoc; }
+
+    SourceLocation getAssertionEndLoc() const {
+      return ValueTokens.size() > 0 ?
+        ValueTokens.back().getLocation() :
+        AssertLoc;
+    }
+
+    /// equals - returns true iff AI has the same tokens as this
+    /// AssertionInfo instance
+    bool equals(AssertionInfo *AI, Preprocessor &PP) const;
+  };
+
+} // end namespace clang
+
+#endif
Index: clang/lib/Lex/AssertionInfo.cpp
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ clang/lib/Lex/AssertionInfo.cpp	2011-12-08 19:19:22.282813700 +1000
@@ -0,0 +1,57 @@
+//===-- AssertionInfo.cpp - AssertionInfo implementation ---------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the declaration of the AssertionInfo class used to track
+// information about GNU-style pre-processor assertions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/AssertionInfo.h"
+#include "clang/Lex/Preprocessor.h"
+
+using namespace clang;
+
+bool AssertionInfo::equals(AssertionInfo *AI, Preprocessor &PP) const {
+  if (ValueTokens.size() != AI->ValueTokens.size()) {
+    return false;
+  }
+
+  for (unsigned i = 0, e = ValueTokens.size(); i != e; ++i) {
+    const Token &A = ValueTokens[i];
+    const Token &B = AI->ValueTokens[i];
+
+    if (A.getKind() != B.getKind()) {
+      return false;
+    }
+
+    // If this isn't the first token, check that the whitespace and
+    // start-of-line characteristics match.
+    if (i != 0 &&
+        (A.isAtStartOfLine() != B.isAtStartOfLine() ||
+         A.hasLeadingSpace() != B.hasLeadingSpace())) {
+      return false;
+    }
+
+    // If the tokens to be compared are identifiers, the comparison is easy
+    if (A.getIdentifierInfo() || B.getIdentifierInfo()) {
+      if (A.getIdentifierInfo() != B.getIdentifierInfo()) {
+        return false;
+      }
+      continue;
+    }
+
+    // Otherwise, check the token spelling
+    if (PP.getSpelling(A) != PP.getSpelling(B)) {
+      return false;
+    }
+  }
+
+  // The tokens all matched
+  return true;
+}
Index: clang/lib/Lex/PPAssertionHandler.cpp
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ clang/lib/Lex/PPAssertionHandler.cpp	2011-12-09 15:11:00.832461300 +1000
@@ -0,0 +1,93 @@
+//===-- PPAssertionHandler.cpp - handling of PP assert/unassert directives -===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the pre-processor methods for handling GNU-style
+// pre-processor asserts and unasserts.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/LexDiagnostic.h"
+
+using namespace clang;
+
+void Preprocessor::addAssertionValue(IdentifierInfo *II, AssertionInfo *AI) {
+  bool alreadyAsserted = false;
+  if (!AssertedValues[II].empty()) {
+    for (assertion_value_iterator I = AssertedValues[II].begin(),
+                                  E = AssertedValues[II].end();
+         I != E; ++I) {
+      if ((*I)->equals(AI, *this)) {
+        alreadyAsserted = true;
+        break;
+      }
+    }
+  }
+
+  if (!alreadyAsserted) {
+    AssertedValues[II].push_back(AI);
+  }
+}
+
+bool Preprocessor::isAsserted(IdentifierInfo *II, AssertionInfo *AI) {
+  if (AssertedValues.find(II) != assertion_end() &&
+      !AssertedValues[II].empty()) {
+    for (assertion_value_iterator I = AssertedValues[II].begin(),
+                                  E = AssertedValues[II].end();
+         I != E; ++I) {
+      if ((*I)->equals(AI, *this)) {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+void Preprocessor::removeAssertionValue(IdentifierInfo *II, AssertionInfo *AI){
+  // check if the assertion predicate is in the assertion table
+  assertion_iterator iter = AssertedValues.find(II);
+
+  // we don't have an entry in the assertion table for the predicate, this is a
+  // noop so escape early
+  if (iter == assertion_end()) {
+    return;
+  }
+
+  for (assertion_value_iterator I = AssertedValues[II].begin(),
+                                E = AssertedValues[II].end();
+       I != E; ++I) {
+    if ((*I)->equals(AI, *this)) {
+      AssertionInfo *toRelease = const_cast<AssertionInfo*>(*I);
+      AssertedValues[II].erase(I);
+      releaseAssertionInfo(toRelease);
+      break;
+    }
+  }
+}
+
+void Preprocessor::removeAssertion(IdentifierInfo *II) {
+  // check if the assertion predicate is in the assertion table
+  assertion_iterator iter = AssertedValues.find(II);
+
+  // we don't have an entry in the assertion table for the predicate, this is a
+  // noop so escape early
+  if (iter == assertion_end()) {
+    return;
+  }
+
+  // deallocate all of the asserted values for the predicate
+  for (assertion_value_iterator I = AssertedValues[II].begin(),
+                                E = AssertedValues[II].end();
+       I != E; ++I) {
+    releaseAssertionInfo(const_cast<AssertionInfo*>(*I));
+  }
+
+  // remove the predicate from the assertion table
+  AssertedValues.erase(II);
+}
Index: clang/lib/Lex/Preprocessor.cpp
===================================================================
--- clang.orig/lib/Lex/Preprocessor.cpp	2011-12-08 19:17:59.000000000 +1000
+++ clang/lib/Lex/Preprocessor.cpp	2011-12-12 16:07:46.779642300 +1000
@@ -62,7 +62,7 @@
     CodeCompletionFile(0), CodeCompletionOffset(0), CodeCompletionReached(0),
     SkipMainFilePreamble(0, true), CurPPLexer(0), 
     CurDirLookup(0), CurLexerKind(CLK_Lexer), Callbacks(0), MacroArgCache(0), 
-    Record(0), MIChainHead(0), MICache(0) 
+    Record(0), MIChainHead(0), MICache(0), AIChainHead(0), AICache(0)
 {
   OwnsHeaderSearch = OwnsHeaders;
   
@@ -85,6 +85,10 @@
   for (MacroInfoChain *I = MIChainHead ; I ; I = I->Next)
     I->MI.Destroy();
 
+  // Free any assertion definitions.
+  for (AssertionInfoChain *I = AIChainHead; I ; I = I->Next)
+    I->AI.destroy();
+
   // Free any cached macro expanders.
   for (unsigned i = 0, e = NumCachedTokenLexers; i != e; ++i)
     delete TokenLexerCache[i];
@@ -251,6 +255,7 @@
     + llvm::capacity_in_bytes(MacroExpandedTokens)
     + Predefines.capacity() /* Predefines buffer. */
     + llvm::capacity_in_bytes(Macros)
+    + llvm::capacity_in_bytes(AssertedValues)
     + llvm::capacity_in_bytes(PragmaPushMacroInfo)
     + llvm::capacity_in_bytes(PoisonReasons)
     + llvm::capacity_in_bytes(CommentHandlers);
@@ -267,6 +272,16 @@
   return Macros.end();
 }
 
+Preprocessor::assertion_iterator
+Preprocessor::assertion_begin() {
+  return AssertedValues.begin();
+}
+
+Preprocessor::assertion_iterator
+Preprocessor::assertion_end() {
+  return AssertedValues.end();
+}
+
 bool Preprocessor::SetCodeCompletionPoint(const FileEntry *File,
                                           unsigned CompleteLine,
                                           unsigned CompleteColumn) {
Index: clang/test/Preprocessor/assertion.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ clang/test/Preprocessor/assertion.c	2011-12-08 19:19:22.431832700 +1000
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -E %s | grep '^A$'
+// RUN: %clang_cc1 -E %s | grep '^NOT C$'
+// RUN: %clang_cc1 -E %s | grep '^NOT A2$'
+// RUN: %clang_cc1 -E %s | grep '^NO TEST$'
+// RUN: %clang_cc1 -E %s | grep '^OK$'
+
+#assert test(A)
+#assert test(B)
+
+#if #test(A)
+A
+#else
+NOT A
+#endif
+
+#if #test(C)
+C
+#else
+NOT C
+#endif
+
+#unassert test(A)
+#if #test(A)
+A2
+#else
+NOT A2
+#endif
+
+#unassert test
+#if #test(A) || #test(B)
+TEST
+#else
+NO TEST
+#endif
+
+#unassert val
+OK
Index: clang/test/Preprocessor/assertion_whitespace.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ clang/test/Preprocessor/assertion_whitespace.c	2011-12-08 19:19:22.476838400 +1000
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -E %s | grep '^INTERNAL$'
+// RUN: %clang_cc1 -E %s | grep '^EXTERNAL1 IGNORED$'
+// RUN: %clang_cc1 -E %s | grep '^EXTERNAL2 IGNORED$'
+
+#assert test(x + y)
+
+#if #test(x+y)
+INTERNAL IGNORED
+#else
+INTERNAL
+#endif
+
+#if #test( x + y)
+EXTERNAL1 IGNORED
+#else
+EXTERNAL1
+#endif
+
+#if #test(x + y )
+EXTERNAL2 IGNORED
+#else
+EXTERNAL2
+#endif
