aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Parse/ParsePragma.cpp80
-rw-r--r--lib/Parse/ParsePragma.h11
-rw-r--r--lib/Parse/Parser.cpp17
-rw-r--r--lib/Sema/Sema.h6
-rw-r--r--lib/Sema/SemaAttr.cpp38
5 files changed, 145 insertions, 7 deletions
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
index 01496b31f7..94695e4d56 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 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, Token &PackTok) {
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 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, Token &PackTok) {
}
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 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, Token &PackTok) {
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 8a9ae5765b..31b2a5f685 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 @@ public:
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 8c3ff443f1..a26c310c20 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -31,9 +31,14 @@ Parser::Parser(Preprocessor &pp, Action &actions)
// 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 @@ Parser::~Parser() {
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.
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index e8702bcea1..a071455276 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -2073,6 +2073,12 @@ public:
SourceLocation LParenLoc,
SourceLocation RParenLoc);
+ /// ActOnPragmaUnused - Called on well-formed '#pragma unused'.
+ virtual void ActOnPragmaUnused(ExprTy **Exprs, unsigned NumExprs,
+ SourceLocation PragmaLoc,
+ SourceLocation LParenLoc,
+ SourceLocation RParenLoc);
+
/// getPragmaPackAlignment() - Return the current alignment as specified by
/// the current #pragma pack directive, or 0 if none is currently active.
unsigned getPragmaPackAlignment() const;
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp
index 37962ad173..a799169f23 100644
--- a/lib/Sema/SemaAttr.cpp
+++ b/lib/Sema/SemaAttr.cpp
@@ -170,3 +170,41 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name,
}
}
+void Sema::ActOnPragmaUnused(ExprTy **Exprs, unsigned NumExprs,
+ SourceLocation PragmaLoc,
+ SourceLocation LParenLoc,
+ SourceLocation RParenLoc) {
+
+ // Verify that all of the expressions are valid before
+ // modifying the attributes of any referenced decl.
+ Expr *ErrorExpr = 0;
+
+ for (unsigned i = 0; i < NumExprs; ++i) {
+ Expr *Ex = (Expr*) Exprs[i];
+ if (!isa<DeclRefExpr>(Ex)) {
+ ErrorExpr = Ex;
+ break;
+ }
+
+ Decl *d = cast<DeclRefExpr>(Ex)->getDecl();;
+
+ if (!isa<VarDecl>(d) || !cast<VarDecl>(d)->hasLocalStorage()) {
+ ErrorExpr = Ex;
+ break;
+ }
+ }
+
+ // Delete the expressions if we encountered any error.
+ if (ErrorExpr) {
+ Diag(ErrorExpr->getLocStart(), diag::warn_pragma_unused_expected_localvar);
+ for (unsigned i = 0; i < NumExprs; ++i)
+ ((Expr*) Exprs[i])->Destroy(Context);
+ return;
+ }
+
+ // Otherwise, add the 'unused' attribute to each referenced declaration.
+ for (unsigned i = 0; i < NumExprs; ++i) {
+ DeclRefExpr *DR = (DeclRefExpr*) Exprs[i];
+ DR->getDecl()->addAttr(::new (Context) UnusedAttr());
+ }
+}