Implement '#pragma unused'.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67569 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
index 01496b3..94695e4 100644
--- a/lib/Parse/ParsePragma.cpp
+++ b/lib/Parse/ParsePragma.cpp
@@ -15,6 +15,7 @@
 #include "clang/Parse/ParseDiagnostic.h"
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Parse/Action.h"
+#include "clang/Parse/Parser.h"
 using namespace clang;
 
 // #pragma pack(...) comes in the following delicious flavors:
@@ -28,7 +29,7 @@
   Token Tok;
   PP.Lex(Tok);
   if (Tok.isNot(tok::l_paren)) {
-    PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_expected_lparen);
+    PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << "pack";
     return;
   }
 
@@ -95,7 +96,7 @@
   }
 
   if (Tok.isNot(tok::r_paren)) {
-    PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_expected_rparen);
+    PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen) << "pack";
     return;
   }
 
@@ -104,3 +105,78 @@
                           LParenLoc, RParenLoc);
 }
 
+// #pragma unused(identifier)
+void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, Token &UnusedTok) {
+  // FIXME: Should we be expanding macros here? My guess is no.
+  SourceLocation UnusedLoc = UnusedTok.getLocation();
+  
+  // Lex the left '('.
+  Token Tok;
+  PP.Lex(Tok);
+  if (Tok.isNot(tok::l_paren)) {
+    PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << "unused";
+    return;
+  }
+  SourceLocation LParenLoc = Tok.getLocation();
+  
+  // Lex the declaration reference(s).
+  llvm::SmallVector<Action::ExprTy*, 5> Ex;
+  SourceLocation RParenLoc;
+  bool LexID = true;
+  
+  while (true) {
+    PP.Lex(Tok);
+    
+    if (LexID) {
+      if (Tok.is(tok::identifier)) {            
+        Action::OwningExprResult Name = 
+          Actions.ActOnIdentifierExpr(parser.CurScope, Tok.getLocation(),
+                                      *Tok.getIdentifierInfo(), false);
+      
+        if (Name.isInvalid()) {
+          if (!Ex.empty())
+            Action::MultiExprArg Release(Actions, &Ex[0], Ex.size());
+          return;
+        }
+        
+        Ex.push_back(Name.release());        
+        LexID = false;
+        continue;
+      }
+
+      // Illegal token! Release the parsed expressions (if any) and emit
+      // a warning.
+      if (!Ex.empty())
+        Action::MultiExprArg Release(Actions, &Ex[0], Ex.size());
+      
+      PP.Diag(Tok.getLocation(), diag::warn_pragma_unused_expected_var);
+      return;
+    }
+    
+    // We are execting a ')' or a ','.
+    if (Tok.is(tok::comma)) {
+      LexID = true;
+      continue;
+    }
+    
+    if (Tok.is(tok::r_paren)) {
+      RParenLoc = Tok.getLocation();
+      break;
+    }
+    
+    // Illegal token! Release the parsed expressions (if any) and emit
+    // a warning.
+    if (!Ex.empty())
+      Action::MultiExprArg Release(Actions, &Ex[0], Ex.size());
+    
+    PP.Diag(Tok.getLocation(), diag::warn_pragma_unused_expected_punc);
+    return;
+  }
+  
+  // Verify that we have a location for the right parenthesis.
+  assert(RParenLoc.isValid() && "Valid '#pragma unused' must have ')'");
+  assert(!Ex.empty() && "Valid '#pragma unused' must have arguments");
+
+  // Perform the action to handle the pragma.    
+  Actions.ActOnPragmaUnused(&Ex[0], Ex.size(), UnusedLoc, LParenLoc, RParenLoc);
+}
diff --git a/lib/Parse/ParsePragma.h b/lib/Parse/ParsePragma.h
index 8a9ae57..31b2a5f 100644
--- a/lib/Parse/ParsePragma.h
+++ b/lib/Parse/ParsePragma.h
@@ -18,6 +18,7 @@
 
 namespace clang {
   class Action;
+  class Parser;
 
 class PragmaPackHandler : public PragmaHandler {
   Action &Actions;
@@ -27,6 +28,16 @@
   
   virtual void HandlePragma(Preprocessor &PP, Token &FirstToken);  
 };
+  
+class PragmaUnusedHandler : public PragmaHandler {
+  Action &Actions;
+  Parser &parser;
+public:
+  PragmaUnusedHandler(const IdentifierInfo *N, Action &A, Parser& p)
+    : PragmaHandler(N), Actions(A), parser(p) {}
+  
+  virtual void HandlePragma(Preprocessor &PP, Token &FirstToken);  
+};  
 
 }  // end namespace clang
 
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 8c3ff44..a26c310 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -31,9 +31,14 @@
 
   // Add #pragma handlers. These are removed and destroyed in the
   // destructor.
-  PackHandler =
-    new PragmaPackHandler(&PP.getIdentifierTable().get("pack"), actions);
-  PP.AddPragmaHandler(0, PackHandler);
+  PackHandler.reset(new
+          PragmaPackHandler(&PP.getIdentifierTable().get("pack"), actions));
+  PP.AddPragmaHandler(0, PackHandler.get());
+      
+  UnusedHandler.reset(new
+          PragmaUnusedHandler(&PP.getIdentifierTable().get("unused"), actions,
+                              *this));
+  PP.AddPragmaHandler(0, UnusedHandler.get());
 
   // Instantiate a LexedMethodsForTopClass for all the non-nested classes.
   PushTopClassStack();
@@ -282,8 +287,10 @@
     delete ScopeCache[i];
 
   // Remove the pragma handlers we installed.
-  PP.RemovePragmaHandler(0, PackHandler);
-  delete PackHandler;
+  PP.RemovePragmaHandler(0, PackHandler.get());
+  PackHandler.reset();
+  PP.RemovePragmaHandler(0, UnusedHandler.get());
+  UnusedHandler.reset();
 }
 
 /// Initialize - Warm up the parser.