diff --git a/include/clang/AST/ASTDiagnostic.h b/include/clang/AST/ASTDiagnostic.h
index 1ab53b3..962dd50 100644
--- a/include/clang/AST/ASTDiagnostic.h
+++ b/include/clang/AST/ASTDiagnostic.h
@@ -15,7 +15,7 @@
 namespace clang {
   namespace diag {
     enum {
-#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM,
+#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY,LEVEL) ENUM,
 #define ASTSTART
 #include "clang/Basic/DiagnosticASTKinds.inc"
 #undef DIAG
diff --git a/include/clang/Analysis/AnalysisDiagnostic.h b/include/clang/Analysis/AnalysisDiagnostic.h
index 295d0a2..53d8e51 100644
--- a/include/clang/Analysis/AnalysisDiagnostic.h
+++ b/include/clang/Analysis/AnalysisDiagnostic.h
@@ -15,7 +15,7 @@
 namespace clang {
   namespace diag {
     enum {
-#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM,
+#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY,LEVEL) ENUM,
 #define ANALYSISSTART
 #include "clang/Basic/DiagnosticAnalysisKinds.inc"
 #undef DIAG
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h
index 3fc60d1..367f8f1 100644
--- a/include/clang/Basic/Diagnostic.h
+++ b/include/clang/Basic/Diagnostic.h
@@ -149,6 +149,7 @@ private:
   bool IgnoreAllWarnings;        // Ignore all warnings: -w
   bool WarningsAsErrors;         // Treat warnings like errors:
   bool ErrorsAsFatal;            // Treat errors like fatal errors.
+  unsigned WarningLevel;         // Keeps the current warning level state.
   bool SuppressSystemWarnings;   // Suppress warnings in system headers.
   bool SuppressAllDiagnostics;   // Suppress all diagnostics.
   OverloadsShown ShowOverloads;  // Which overload candidates to show.
@@ -173,17 +174,35 @@ private:
   /// source location.
   class DiagState {
     llvm::DenseMap<unsigned, unsigned> DiagMap;
+    unsigned                           WarningLevel;
 
   public:
+    explicit DiagState(unsigned WarningLevel)
+      : WarningLevel(WarningLevel) {}
+
     typedef llvm::DenseMap<unsigned, unsigned>::const_iterator iterator;
 
+    unsigned getWarningLevel() const { return WarningLevel; }
+    void setWarningLevel(unsigned Level){ WarningLevel = Level; }
+
     void setMapping(diag::kind Diag, unsigned Map) { DiagMap[Diag] = Map; }
 
     diag::Mapping getMapping(diag::kind Diag) const {
       iterator I = DiagMap.find(Diag);
       if (I != DiagMap.end())
         return (diag::Mapping)I->second;
-      return diag::Mapping();
+
+      // Otherwise, find out if this is a warning and enabled at this
+      // level.
+      bool     IsWarning        = false;
+      unsigned DiagWarningLevel = 0;
+
+      DiagnosticIDs::getWarningLevel(Diag,IsWarning,DiagWarningLevel);
+      if(IsWarning && DiagWarningLevel > getWarningLevel()) {
+        return diag::MAP_IGNORE;
+      } else {
+        return diag::Mapping();
+      };
     }
 
     iterator begin() const { return DiagMap.begin(); }
@@ -352,7 +371,10 @@ public:
   unsigned getTemplateBacktraceLimit() const {
     return TemplateBacktraceLimit;
   }
-  
+
+  void setWarningLevel(unsigned Level, SourceLocation Loc);
+  unsigned getWarningLevel() const;
+
   /// setIgnoreAllWarnings - When set to true, any unmapped warnings are
   /// ignored.  If this and WarningsAsErrors are both set, then this one wins.
   void setIgnoreAllWarnings(bool Val) { IgnoreAllWarnings = Val; }
diff --git a/include/clang/Basic/Diagnostic.td b/include/clang/Basic/Diagnostic.td
index be510ed..1266006 100644
--- a/include/clang/Basic/Diagnostic.td
+++ b/include/clang/Basic/Diagnostic.td
@@ -60,6 +60,7 @@ class Diagnostic<string text, DiagClass DC, DiagMapping defaultmapping> {
   DiagMapping DefaultMapping = defaultmapping;
   DiagGroup   Group;
   string      CategoryName = "";
+  int         WarningEnabledAtLevel = 1;
 }
 
 class Error<string str>     : Diagnostic<str, CLASS_ERROR, MAP_ERROR>;
@@ -74,6 +75,8 @@ class DefaultWarn   { DiagMapping DefaultMapping = MAP_WARNING; }
 class DefaultError  { DiagMapping DefaultMapping = MAP_ERROR; }
 class DefaultFatal  { DiagMapping DefaultMapping = MAP_FATAL; }
 
+class WarningLevel<int level> { int WarningEnabledAtLevel = level; }
+
 class NoSFINAE { bit SFINAE = 0; }
 class AccessControl { bit AccessControl = 1; }
 
diff --git a/include/clang/Basic/DiagnosticIDs.h b/include/clang/Basic/DiagnosticIDs.h
index 3b85e73..52cb212 100644
--- a/include/clang/Basic/DiagnosticIDs.h
+++ b/include/clang/Basic/DiagnosticIDs.h
@@ -42,7 +42,7 @@ namespace clang {
 
     // Get typedefs for common diagnostics.
     enum {
-#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM,
+#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY,LEVEL) ENUM,
 #include "clang/Basic/DiagnosticCommonKinds.inc"
       NUM_BUILTIN_COMMON_DIAGNOSTICS
 #undef DIAG
@@ -137,6 +137,8 @@ public:
   /// getCategoryNameFromID - Given a category ID, return the name of the
   /// category.
   static const char *getCategoryNameFromID(unsigned CategoryID);
+
+  static void getWarningLevel(unsigned DiagID, bool & IsWarning, unsigned & WarningLevel);
   
   /// \brief Enumeration describing how the the emission of a diagnostic should
   /// be treated when it occurs during C++ template argument deduction.
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 28dc0aa..7fdf848 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -215,7 +215,8 @@ def warn_maybe_falloff_nonvoid_function : Warning<
   InGroup<ReturnType>;
 def warn_falloff_nonvoid_function : Warning<
   "control reaches end of non-void function">,
-  InGroup<ReturnType>;
+  InGroup<ReturnType>,
+  WarningLevel<3>;
 def err_maybe_falloff_nonvoid_block : Error<
   "control may reach end of non-void block">;
 def err_falloff_nonvoid_block : Error<
diff --git a/include/clang/Driver/DriverDiagnostic.h b/include/clang/Driver/DriverDiagnostic.h
index 0733c51..61cfb3b 100644
--- a/include/clang/Driver/DriverDiagnostic.h
+++ b/include/clang/Driver/DriverDiagnostic.h
@@ -15,7 +15,7 @@
 namespace clang {
   namespace diag {
     enum {
-#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM,
+#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY,LEVEL) ENUM,
 #define DRIVERSTART
 #include "clang/Basic/DiagnosticDriverKinds.inc"
 #undef DIAG
diff --git a/include/clang/Frontend/FrontendDiagnostic.h b/include/clang/Frontend/FrontendDiagnostic.h
index 2efbc81..78ec03c 100644
--- a/include/clang/Frontend/FrontendDiagnostic.h
+++ b/include/clang/Frontend/FrontendDiagnostic.h
@@ -15,7 +15,7 @@
 namespace clang {
   namespace diag {
     enum {
-#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM,
+#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY,LEVEL) ENUM,
 #define FRONTENDSTART
 #include "clang/Basic/DiagnosticFrontendKinds.inc"
 #undef DIAG
diff --git a/include/clang/Lex/LexDiagnostic.h b/include/clang/Lex/LexDiagnostic.h
index 5fcb8eb..2707779 100644
--- a/include/clang/Lex/LexDiagnostic.h
+++ b/include/clang/Lex/LexDiagnostic.h
@@ -15,7 +15,7 @@
 namespace clang {
   namespace diag {
     enum {
-#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM,
+#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY,LEVEL) ENUM,
 #define LEXSTART
 #include "clang/Basic/DiagnosticLexKinds.inc"
 #undef DIAG
diff --git a/include/clang/Parse/ParseDiagnostic.h b/include/clang/Parse/ParseDiagnostic.h
index f640b37..0857c52 100644
--- a/include/clang/Parse/ParseDiagnostic.h
+++ b/include/clang/Parse/ParseDiagnostic.h
@@ -15,7 +15,7 @@
 namespace clang {
   namespace diag {
     enum {
-#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM,
+#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY,LEVEL) ENUM,
 #define PARSESTART
 #include "clang/Basic/DiagnosticParseKinds.inc"
 #undef DIAG
diff --git a/include/clang/Sema/SemaDiagnostic.h b/include/clang/Sema/SemaDiagnostic.h
index ae5aa33..1629c4b 100644
--- a/include/clang/Sema/SemaDiagnostic.h
+++ b/include/clang/Sema/SemaDiagnostic.h
@@ -15,7 +15,7 @@
 namespace clang {
   namespace diag {
     enum {
-#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM,
+#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY,LEVEL) ENUM,
 #define SEMASTART
 #include "clang/Basic/DiagnosticSemaKinds.inc"
 #undef DIAG
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index 31e3331..2ad5571 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -37,21 +37,22 @@ Diagnostic::Diagnostic(const llvm::IntrusiveRefCntPtr<DiagnosticIDs> &diags,
   ArgToStringFn = DummyArgToStringFn;
   ArgToStringCookie = 0;
 
-  AllExtensionsSilenced = 0;
-  IgnoreAllWarnings = false;
-  WarningsAsErrors = false;
-  ErrorsAsFatal = false;
+  AllExtensionsSilenced  = 0;
+  IgnoreAllWarnings      = false;
+  WarningsAsErrors       = false;
+  WarningLevel           = 4; // FIXME: Magic number
+  ErrorsAsFatal          = false;
   SuppressSystemWarnings = false;
   SuppressAllDiagnostics = false;
-  ShowOverloads = Ovl_All;
-  ExtBehavior = Ext_Ignore;
+  ShowOverloads          = Ovl_All;
+  ExtBehavior            = Ext_Ignore;
 
   ErrorLimit = 0;
   TemplateBacktraceLimit = 0;
 
   // Create a DiagState and DiagStatePoint representing diagnostic changes
   // through command-line.
-  DiagStates.push_back(DiagState());
+  DiagStates.push_back(DiagState(WarningLevel));
   PushDiagStatePoint(&DiagStates.back(), SourceLocation());
 
   Reset();
@@ -685,3 +686,52 @@ PartialDiagnostic::StorageAllocator::StorageAllocator() {
 PartialDiagnostic::StorageAllocator::~StorageAllocator() {
   assert(NumFreeListEntries == NumCached && "A partial is on the lamb");
 }
+
+void
+Diagnostic::setWarningLevel(unsigned Level, SourceLocation L) {
+  // See the logic in setDiagnosticMapping for explanation of the
+  // logic here.
+  assert(!DiagStatePoints.empty());
+
+  FullSourceLoc Loc(L, *SourceMgr);
+  FullSourceLoc LastStateChangePos = DiagStatePoints.back().Loc;
+
+  if(Loc.isInvalid() || Loc == LastStateChangePos) {
+    GetCurDiagState()->setWarningLevel(Level);
+    return;
+  }
+
+  if ((Loc.isValid() && LastStateChangePos.isInvalid()) ||
+      LastStateChangePos.isBeforeInTranslationUnitThan(Loc)) {
+    DiagStates.push_back(*GetCurDiagState());
+    PushDiagStatePoint(&DiagStates.back(),Loc);
+    GetCurDiagState()->setWarningLevel(Level);
+    return;
+  }
+
+  DiagStatePointsTy::iterator Pos = GetDiagStatePointForLoc(Loc);
+  assert(Pos != DiagStatePoints.end());
+
+  for(DiagStatePointsTy::iterator I = Pos + 1, E = DiagStatePoints.end();
+      I != E;
+      ++I) {
+    I->State->setWarningLevel(Level);
+  }
+
+  if(Pos->Loc == Loc) {
+    Pos->State->setWarningLevel(Level);
+    return;
+  }
+
+  Pos->Loc.isBeforeInTranslationUnitThan(Loc);
+  DiagStates.push_back(*Pos->State);
+  DiagState *NewState = &DiagStates.back();
+  NewState->setWarningLevel(Level);
+  DiagStatePoints.insert(Pos+1, DiagStatePoint(NewState,
+                                               FullSourceLoc(Loc,*SourceMgr)));
+}
+
+unsigned
+Diagnostic::getWarningLevel() const {
+  return GetCurDiagState()->getWarningLevel();
+}
diff --git a/lib/Basic/DiagnosticIDs.cpp b/lib/Basic/DiagnosticIDs.cpp
index 553e4c9..61bdddc 100644
--- a/lib/Basic/DiagnosticIDs.cpp
+++ b/lib/Basic/DiagnosticIDs.cpp
@@ -45,10 +45,12 @@ struct StaticDiagInfoRec {
   unsigned SFINAE : 1;
   unsigned AccessControl : 1;
   unsigned Category : 5;
-  
+
   const char *Description;
   const char *OptionGroup;
 
+  unsigned WarningEnabledAtLevel: 2;
+
   bool operator<(const StaticDiagInfoRec &RHS) const {
     return DiagID < RHS.DiagID;
   }
@@ -57,8 +59,8 @@ struct StaticDiagInfoRec {
 }
 
 static const StaticDiagInfoRec StaticDiagInfo[] = {
-#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY)    \
-  { diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE, ACCESS, CATEGORY, DESC, GROUP },
+#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY, LEVEL) \
+  { diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE, ACCESS, CATEGORY, DESC, GROUP, LEVEL },
 #include "clang/Basic/DiagnosticCommonKinds.inc"
 #include "clang/Basic/DiagnosticDriverKinds.inc"
 #include "clang/Basic/DiagnosticFrontendKinds.inc"
@@ -67,7 +69,7 @@ static const StaticDiagInfoRec StaticDiagInfo[] = {
 #include "clang/Basic/DiagnosticASTKinds.inc"
 #include "clang/Basic/DiagnosticSemaKinds.inc"
 #include "clang/Basic/DiagnosticAnalysisKinds.inc"
-  { 0, 0, 0, 0, 0, 0, 0, 0}
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0}
 };
 #undef DIAG
 
@@ -93,7 +95,7 @@ static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) {
 #endif
 
   // Search the diagnostic table with a binary search.
-  StaticDiagInfoRec Find = { DiagID, 0, 0, 0, 0, 0, 0, 0 };
+  StaticDiagInfoRec Find = { DiagID, 0, 0, 0, 0, 0, 0, 0, 0 };
 
   const StaticDiagInfoRec *Found =
     std::lower_bound(StaticDiagInfo, StaticDiagInfo + NumDiagEntries, Find);
@@ -299,6 +301,19 @@ DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, SourceLocation Loc,
   return getDiagnosticLevel(DiagID, DiagClass, Loc, Diag, mapping);
 }
 
+void
+DiagnosticIDs::getWarningLevel(unsigned DiagID,
+                               bool & IsWarning, unsigned & DiagWarningLevel) {
+  const StaticDiagInfoRec *S = GetDiagInfo(DiagID);
+  if(!S) {
+    IsWarning = false;
+    return;
+  } else {
+    IsWarning        = S->Class == CLASS_WARNING;
+    DiagWarningLevel = S->WarningEnabledAtLevel;
+  }
+}
+
 /// \brief Based on the way the client configured the Diagnostic
 /// object, classify the specified diagnostic ID into a Level, consumable by
 /// the DiagnosticClient.
diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp
index 8f11d4b..e58b080 100644
--- a/lib/Lex/Pragma.cpp
+++ b/lib/Lex/Pragma.cpp
@@ -1229,7 +1229,6 @@ void PragmaWarningHandler::HandlePragma(Preprocessor &PP,
   IdentifierInfo* II = Tok.getIdentifierInfo();
 
   if (II && II->isStr("push")) {
-    // FIXME: Handle global warning level
     PP.getDiagnostics().pushMappings(WarningLoc);
 
     PP.LexUnexpandedToken(Tok);
@@ -1243,7 +1242,7 @@ void PragmaWarningHandler::HandlePragma(Preprocessor &PP,
       }
       unsigned Level = PP.getSpellingOfSingleCharacterNumericConstant(Tok)
         - '0';
-      (void)Level; // FIXME: do something with level
+      PP.getDiagnostics().setWarningLevel(Level, WarningLoc);
       PP.LexUnexpandedToken(Tok);
     }
 
diff --git a/test/Preprocessor/pragma_warning.c b/test/Preprocessor/pragma_warning.c
index 045c77d..4daf493 100644
--- a/test/Preprocessor/pragma_warning.c
+++ b/test/Preprocessor/pragma_warning.c
@@ -1,5 +1,21 @@
 // RUN: %clang_cc1 %s -fsyntax-only -verify -fms-extensions
 
+// Testing warning levels. Default warning level is 4 but we'll be specific
+#pragma warning(push, 4)
+int f1()
+{
+} // expected-warning{{control reaches end of non-void function}}
+
+// above warning is enabled at level 3 so we disable it now
+#pragma warning(push, 2)
+
+int f3()
+{
+}
+
+#pragma warning(pop) // 2
+#pragma warning(pop) // 4
+
 int f()
 {
 } // expected-warning{{control reaches end of non-void function}}
@@ -17,3 +33,4 @@ int h()
 
 #pragma warning(suppress : 10000)
 #pragma warning(once : 10000; disable: 4715)
+
