forked from OSchip/llvm-project
Convert "#pragma unused(...)" into tokens for the parser.
This allows us to cache a "#pragma unused" that occurs inside an inline C++ member function. Fixes rdar://8829590&8770988. llvm-svn: 123666
This commit is contained in:
parent
834c373e3f
commit
ee56962cc1
|
@ -433,6 +433,12 @@ ANNOTATION(typename) // annotation for a C typedef name, a C++ (possibly
|
||||||
ANNOTATION(template_id) // annotation for a C++ template-id that names a
|
ANNOTATION(template_id) // annotation for a C++ template-id that names a
|
||||||
// function template specialization (not a type),
|
// function template specialization (not a type),
|
||||||
// e.g., "std::swap<int>"
|
// e.g., "std::swap<int>"
|
||||||
|
|
||||||
|
// Annotation for #pragma unused(...)
|
||||||
|
// For each argument inside the parentheses the pragma handler will produce
|
||||||
|
// one 'pragma_unused' annotation token followed by the argument token.
|
||||||
|
ANNOTATION(pragma_unused)
|
||||||
|
|
||||||
#undef ANNOTATION
|
#undef ANNOTATION
|
||||||
#undef OBJC2_AT_KEYWORD
|
#undef OBJC2_AT_KEYWORD
|
||||||
#undef OBJC1_AT_KEYWORD
|
#undef OBJC1_AT_KEYWORD
|
||||||
|
|
|
@ -349,6 +349,9 @@ private:
|
||||||
/// based on context.
|
/// based on context.
|
||||||
void CodeCompletionRecovery();
|
void CodeCompletionRecovery();
|
||||||
|
|
||||||
|
/// \brief Handle the annotation token produced for #pragma unused(...)
|
||||||
|
void HandlePragmaUnused();
|
||||||
|
|
||||||
/// GetLookAheadToken - This peeks ahead N tokens and returns that token
|
/// GetLookAheadToken - This peeks ahead N tokens and returns that token
|
||||||
/// without consuming any tokens. LookAhead(0) returns 'Tok', LookAhead(1)
|
/// without consuming any tokens. LookAhead(0) returns 'Tok', LookAhead(1)
|
||||||
/// returns the token after Tok, etc.
|
/// returns the token after Tok, etc.
|
||||||
|
|
|
@ -4299,11 +4299,9 @@ public:
|
||||||
SourceLocation RParenLoc);
|
SourceLocation RParenLoc);
|
||||||
|
|
||||||
/// ActOnPragmaUnused - Called on well-formed '#pragma unused'.
|
/// ActOnPragmaUnused - Called on well-formed '#pragma unused'.
|
||||||
void ActOnPragmaUnused(const Token *Identifiers,
|
void ActOnPragmaUnused(const Token &Identifier,
|
||||||
unsigned NumIdentifiers, Scope *curScope,
|
Scope *curScope,
|
||||||
SourceLocation PragmaLoc,
|
SourceLocation PragmaLoc);
|
||||||
SourceLocation LParenLoc,
|
|
||||||
SourceLocation RParenLoc);
|
|
||||||
|
|
||||||
/// ActOnPragmaVisibility - Called on well formed #pragma GCC visibility... .
|
/// ActOnPragmaVisibility - Called on well formed #pragma GCC visibility... .
|
||||||
void ActOnPragmaVisibility(bool IsPush, const IdentifierInfo* VisType,
|
void ActOnPragmaVisibility(bool IsPush, const IdentifierInfo* VisType,
|
||||||
|
|
|
@ -17,6 +17,17 @@
|
||||||
#include "clang/Lex/Preprocessor.h"
|
#include "clang/Lex/Preprocessor.h"
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
|
|
||||||
|
/// \brief Handle the annotation token produced for #pragma unused(...)
|
||||||
|
///
|
||||||
|
/// Each annot_pragma_unused is followed by the argument token so e.g.
|
||||||
|
/// "#pragma unused(x,y)" becomes:
|
||||||
|
/// annot_pragma_unused 'x' annot_pragma_unused 'y'
|
||||||
|
void Parser::HandlePragmaUnused() {
|
||||||
|
assert(Tok.is(tok::annot_pragma_unused));
|
||||||
|
SourceLocation UnusedLoc = ConsumeToken();
|
||||||
|
Actions.ActOnPragmaUnused(Tok, getCurScope(), UnusedLoc);
|
||||||
|
ConsumeToken(); // The argument token.
|
||||||
|
}
|
||||||
|
|
||||||
// #pragma GCC visibility comes in two variants:
|
// #pragma GCC visibility comes in two variants:
|
||||||
// 'push' '(' [visibility] ')'
|
// 'push' '(' [visibility] ')'
|
||||||
|
@ -301,9 +312,20 @@ void PragmaUnusedHandler::HandlePragma(Preprocessor &PP,
|
||||||
assert(RParenLoc.isValid() && "Valid '#pragma unused' must have ')'");
|
assert(RParenLoc.isValid() && "Valid '#pragma unused' must have ')'");
|
||||||
assert(!Identifiers.empty() && "Valid '#pragma unused' must have arguments");
|
assert(!Identifiers.empty() && "Valid '#pragma unused' must have arguments");
|
||||||
|
|
||||||
// Perform the action to handle the pragma.
|
// For each identifier token, insert into the token stream a
|
||||||
Actions.ActOnPragmaUnused(Identifiers.data(), Identifiers.size(),
|
// annot_pragma_unused token followed by the identifier token.
|
||||||
parser.getCurScope(), UnusedLoc, LParenLoc, RParenLoc);
|
// This allows us to cache a "#pragma unused" that occurs inside an inline
|
||||||
|
// C++ member function.
|
||||||
|
|
||||||
|
Token *Toks = new Token[2*Identifiers.size()];
|
||||||
|
for (unsigned i=0; i != Identifiers.size(); i++) {
|
||||||
|
Token &pragmaUnusedTok = Toks[2*i], &idTok = Toks[2*i+1];
|
||||||
|
pragmaUnusedTok.startToken();
|
||||||
|
pragmaUnusedTok.setKind(tok::annot_pragma_unused);
|
||||||
|
pragmaUnusedTok.setLocation(UnusedLoc);
|
||||||
|
idTok = Identifiers[i];
|
||||||
|
}
|
||||||
|
PP.EnterTokenStream(Toks, 2*Identifiers.size(), /*DisableMacroExpansion=*/true, /*OwnsTokens=*/true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// #pragma weak identifier
|
// #pragma weak identifier
|
||||||
|
|
|
@ -465,6 +465,12 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
|
||||||
|
|
||||||
StmtVector Stmts(Actions);
|
StmtVector Stmts(Actions);
|
||||||
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
|
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
|
||||||
|
|
||||||
|
if (Tok.is(tok::annot_pragma_unused)) {
|
||||||
|
HandlePragmaUnused();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
StmtResult R;
|
StmtResult R;
|
||||||
if (Tok.isNot(tok::kw___extension__)) {
|
if (Tok.isNot(tok::kw___extension__)) {
|
||||||
R = ParseStatementOrDeclaration(Stmts, false);
|
R = ParseStatementOrDeclaration(Stmts, false);
|
||||||
|
|
|
@ -404,6 +404,10 @@ void Parser::Initialize() {
|
||||||
/// ParseTopLevelDecl - Parse one top-level declaration, return whatever the
|
/// ParseTopLevelDecl - Parse one top-level declaration, return whatever the
|
||||||
/// action tells us to. This returns true if the EOF was encountered.
|
/// action tells us to. This returns true if the EOF was encountered.
|
||||||
bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) {
|
bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) {
|
||||||
|
|
||||||
|
while (Tok.is(tok::annot_pragma_unused))
|
||||||
|
HandlePragmaUnused();
|
||||||
|
|
||||||
Result = DeclGroupPtrTy();
|
Result = DeclGroupPtrTy();
|
||||||
if (Tok.is(tok::eof)) {
|
if (Tok.is(tok::eof)) {
|
||||||
Actions.ActOnEndOfTranslationUnit();
|
Actions.ActOnEndOfTranslationUnit();
|
||||||
|
|
|
@ -263,37 +263,31 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sema::ActOnPragmaUnused(const Token *Identifiers, unsigned NumIdentifiers,
|
void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope,
|
||||||
Scope *curScope,
|
SourceLocation PragmaLoc) {
|
||||||
SourceLocation PragmaLoc,
|
|
||||||
SourceLocation LParenLoc,
|
|
||||||
SourceLocation RParenLoc) {
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < NumIdentifiers; ++i) {
|
IdentifierInfo *Name = IdTok.getIdentifierInfo();
|
||||||
const Token &Tok = Identifiers[i];
|
LookupResult Lookup(*this, Name, IdTok.getLocation(), LookupOrdinaryName);
|
||||||
IdentifierInfo *Name = Tok.getIdentifierInfo();
|
LookupParsedName(Lookup, curScope, NULL, true);
|
||||||
LookupResult Lookup(*this, Name, Tok.getLocation(), LookupOrdinaryName);
|
|
||||||
LookupParsedName(Lookup, curScope, NULL, true);
|
|
||||||
|
|
||||||
if (Lookup.empty()) {
|
if (Lookup.empty()) {
|
||||||
Diag(PragmaLoc, diag::warn_pragma_unused_undeclared_var)
|
Diag(PragmaLoc, diag::warn_pragma_unused_undeclared_var)
|
||||||
<< Name << SourceRange(Tok.getLocation());
|
<< Name << SourceRange(IdTok.getLocation());
|
||||||
continue;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
VarDecl *VD = Lookup.getAsSingle<VarDecl>();
|
|
||||||
if (!VD || !(VD->hasLocalStorage() || VD->isStaticLocal())) {
|
|
||||||
Diag(PragmaLoc, diag::warn_pragma_unused_expected_localvar)
|
|
||||||
<< Name << SourceRange(Tok.getLocation());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Warn if this was used before being marked unused.
|
|
||||||
if (VD->isUsed())
|
|
||||||
Diag(PragmaLoc, diag::warn_used_but_marked_unused) << Name;
|
|
||||||
|
|
||||||
VD->addAttr(::new (Context) UnusedAttr(Tok.getLocation(), Context));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VarDecl *VD = Lookup.getAsSingle<VarDecl>();
|
||||||
|
if (!VD || !(VD->hasLocalStorage() || VD->isStaticLocal())) {
|
||||||
|
Diag(PragmaLoc, diag::warn_pragma_unused_expected_localvar)
|
||||||
|
<< Name << SourceRange(IdTok.getLocation());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warn if this was used before being marked unused.
|
||||||
|
if (VD->isUsed())
|
||||||
|
Diag(PragmaLoc, diag::warn_used_but_marked_unused) << Name;
|
||||||
|
|
||||||
|
VD->addAttr(::new (Context) UnusedAttr(IdTok.getLocation(), Context));
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef std::vector<std::pair<unsigned, SourceLocation> > VisStack;
|
typedef std::vector<std::pair<unsigned, SourceLocation> > VisStack;
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
// RUN: %clang_cc1 -fsyntax-only -Wunused-parameter -Wunused -verify %s
|
||||||
|
|
||||||
|
struct S {
|
||||||
|
void m(int x, int y) {
|
||||||
|
int z;
|
||||||
|
#pragma unused(x,y,z)
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in New Issue