Implement '#pragma unused'.

llvm-svn: 67569
This commit is contained in:
Ted Kremenek 2009-03-23 22:28:25 +00:00
parent c8e54db801
commit fd14fade2f
10 changed files with 213 additions and 15 deletions

View File

@ -234,16 +234,24 @@ def warn_cxx0x_right_shift_in_template_arg : Warning<
// Language specific pragmas
// #pragma pack
def warn_pragma_pack_expected_lparen : Warning<
"missing '(' after '#pragma pack' - ignoring">;
def warn_pragma_pack_expected_rparen : Warning<
"missing ')' after '#pragma pack' - ignoring">;
// - Generic warnings
def warn_pragma_expected_lparen : Warning<
"missing '(' after '#pragma %0' - ignoring">;
def warn_pragma_expected_rparen : Warning<
"missing ')' after '#pragma %0' - ignoring">;
def warn_pragma_expected_identifier : Warning<
"expected identifier in '#pragma %0' - ignored">;
// - #pragma pack
def warn_pragma_pack_invalid_action : Warning<
"unknown action for '#pragma pack' - ignored">;
def warn_pragma_pack_invalid_constant : Warning<
"invalid constant for '#pragma pack', expected %0 - ignored">;
def warn_pragma_pack_malformed : Warning<
"expected integer or identifier in '#pragma pack' - ignored">;
}
// - #pragma unused
def warn_pragma_unused_expected_var : Warning<
"expected '#pragma unused' argument to be a variable name">;
def warn_pragma_unused_expected_punc : Warning<
"expected ')' or ',' in '#pragma unused'">;
} // end of Parser diagnostics

View File

@ -117,6 +117,8 @@ def warn_pragma_pack_pop_identifer_and_alignment : Warning<
"specifying both a name and alignment to 'pop' is undefined">;
def warn_pragma_pack_pop_failed : Warning<"#pragma pack(pop, ...) failed: %0">;
def warn_pragma_unused_expected_localvar : Warning<
"only local variables can be arguments to '#pragma unused'">;
/// Objective-C parser diagnostics
def err_duplicate_class_def : Error<

View File

@ -1483,6 +1483,14 @@ public:
SourceLocation RParenLoc) {
return;
}
/// ActOnPragmaPack - Called on well formed #pragma pack(...).
virtual void ActOnPragmaUnused(ExprTy **Exprs, unsigned NumExprs,
SourceLocation PragmaLoc,
SourceLocation LParenLoc,
SourceLocation RParenLoc) {
return;
}
};
/// MinimalAction - Minimal actions are used by light-weight clients of the

View File

@ -17,6 +17,7 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/Action.h"
#include "clang/Parse/DeclSpec.h"
#include "llvm/ADT/OwningPtr.h"
#include <stack>
#include <list>
@ -26,6 +27,7 @@ namespace clang {
class Scope;
class DiagnosticBuilder;
class Parser;
class PragmaUnusedHandler;
/// PrettyStackTraceParserEntry - If a crash happens while the parser is active,
/// an entry is printed for it.
@ -42,6 +44,7 @@ public:
/// been read.
///
class Parser {
friend class PragmaUnusedHandler;
PrettyStackTraceParserEntry CrashInfo;
Preprocessor &PP;
@ -75,7 +78,8 @@ class Parser {
/// comparison.
IdentifierInfo *Ident_super;
PragmaHandler *PackHandler;
llvm::OwningPtr<PragmaHandler> PackHandler;
llvm::OwningPtr<PragmaHandler> UnusedHandler;
/// Whether the '>' token acts as an operator or not. This will be
/// true except when we are parsing an expression within a C++

View File

@ -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);
}

View File

@ -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

View File

@ -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.

View File

@ -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;

View File

@ -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());
}
}

View File

@ -0,0 +1,38 @@
// RUN: clang -fsyntax-only -verify %s
void f1(void) {
int x, y, z;
#pragma unused(x)
#pragma unused(y, z)
int w; // FIXME: We should emit a warning that 'w' is unused.
#pragma unused w // expected-warning{{missing '(' after '#pragma unused' - ignoring}}
}
void f2(void) {
int x, y;
#pragma unused(x,) // expected-warning{{expected '#pragma unused' argument to be a variable name}}
#pragma unused() // expected-warning{{expected '#pragma unused' argument to be a variable name}}
}
void f3(void) {
#pragma unused(x) // expected-error{{use of undeclared identifier 'x'}}
}
void f4(void) {
int w; // FIXME: We should emit a warning that 'w' is unused.
#pragma unused((w)) // expected-warning{{expected '#pragma unused' argument to be a variable name}}
}
int k;
void f5(void) {
#pragma unused(k) // expected-warning{{only local variables can be arguments to '#pragma unused' - ignored}}
}
void f6(void) {
int z; // no-warning
{
#pragma unused(z) // no-warning
}
}