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.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@123666 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def
index c61930e..86f6d1d 100644
--- a/include/clang/Basic/TokenKinds.def
+++ b/include/clang/Basic/TokenKinds.def
@@ -433,6 +433,12 @@
ANNOTATION(template_id) // annotation for a C++ template-id that names a
// function template specialization (not a type),
// 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 OBJC2_AT_KEYWORD
#undef OBJC1_AT_KEYWORD
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 4e7de34..4ac9eb9 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -349,6 +349,9 @@
/// based on context.
void CodeCompletionRecovery();
+ /// \brief Handle the annotation token produced for #pragma unused(...)
+ void HandlePragmaUnused();
+
/// GetLookAheadToken - This peeks ahead N tokens and returns that token
/// without consuming any tokens. LookAhead(0) returns 'Tok', LookAhead(1)
/// returns the token after Tok, etc.
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 76b5f52..61c4ec4 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -4299,11 +4299,9 @@
SourceLocation RParenLoc);
/// ActOnPragmaUnused - Called on well-formed '#pragma unused'.
- void ActOnPragmaUnused(const Token *Identifiers,
- unsigned NumIdentifiers, Scope *curScope,
- SourceLocation PragmaLoc,
- SourceLocation LParenLoc,
- SourceLocation RParenLoc);
+ void ActOnPragmaUnused(const Token &Identifier,
+ Scope *curScope,
+ SourceLocation PragmaLoc);
/// ActOnPragmaVisibility - Called on well formed #pragma GCC visibility... .
void ActOnPragmaVisibility(bool IsPush, const IdentifierInfo* VisType,
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
index 42c1c5f..90c7d76 100644
--- a/lib/Parse/ParsePragma.cpp
+++ b/lib/Parse/ParsePragma.cpp
@@ -17,6 +17,17 @@
#include "clang/Lex/Preprocessor.h"
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:
// 'push' '(' [visibility] ')'
@@ -301,9 +312,20 @@
assert(RParenLoc.isValid() && "Valid '#pragma unused' must have ')'");
assert(!Identifiers.empty() && "Valid '#pragma unused' must have arguments");
- // Perform the action to handle the pragma.
- Actions.ActOnPragmaUnused(Identifiers.data(), Identifiers.size(),
- parser.getCurScope(), UnusedLoc, LParenLoc, RParenLoc);
+ // For each identifier token, insert into the token stream a
+ // annot_pragma_unused token followed by the identifier token.
+ // 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
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index b1d40d2..113b266 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -465,6 +465,12 @@
StmtVector Stmts(Actions);
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
+
+ if (Tok.is(tok::annot_pragma_unused)) {
+ HandlePragmaUnused();
+ continue;
+ }
+
StmtResult R;
if (Tok.isNot(tok::kw___extension__)) {
R = ParseStatementOrDeclaration(Stmts, false);
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 473c6ad..47c6237 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -404,6 +404,10 @@
/// ParseTopLevelDecl - Parse one top-level declaration, return whatever the
/// action tells us to. This returns true if the EOF was encountered.
bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) {
+
+ while (Tok.is(tok::annot_pragma_unused))
+ HandlePragmaUnused();
+
Result = DeclGroupPtrTy();
if (Tok.is(tok::eof)) {
Actions.ActOnEndOfTranslationUnit();
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp
index de1e1bf..a67c4fb 100644
--- a/lib/Sema/SemaAttr.cpp
+++ b/lib/Sema/SemaAttr.cpp
@@ -263,37 +263,31 @@
}
}
-void Sema::ActOnPragmaUnused(const Token *Identifiers, unsigned NumIdentifiers,
- Scope *curScope,
- SourceLocation PragmaLoc,
- SourceLocation LParenLoc,
- SourceLocation RParenLoc) {
+void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope,
+ SourceLocation PragmaLoc) {
- for (unsigned i = 0; i < NumIdentifiers; ++i) {
- const Token &Tok = Identifiers[i];
- IdentifierInfo *Name = Tok.getIdentifierInfo();
- LookupResult Lookup(*this, Name, Tok.getLocation(), LookupOrdinaryName);
- LookupParsedName(Lookup, curScope, NULL, true);
+ IdentifierInfo *Name = IdTok.getIdentifierInfo();
+ LookupResult Lookup(*this, Name, IdTok.getLocation(), LookupOrdinaryName);
+ LookupParsedName(Lookup, curScope, NULL, true);
- if (Lookup.empty()) {
- Diag(PragmaLoc, diag::warn_pragma_unused_undeclared_var)
- << Name << SourceRange(Tok.getLocation());
- continue;
- }
-
- 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));
+ if (Lookup.empty()) {
+ Diag(PragmaLoc, diag::warn_pragma_unused_undeclared_var)
+ << Name << SourceRange(IdTok.getLocation());
+ return;
}
+
+ 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;
diff --git a/test/SemaCXX/pragma-unused.cpp b/test/SemaCXX/pragma-unused.cpp
new file mode 100644
index 0000000..c9ddffa
--- /dev/null
+++ b/test/SemaCXX/pragma-unused.cpp
@@ -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)
+ }
+};