Skip to content

Commit 6bf6791

Browse files
committed
[NFC] Use RAII to un-poison and then re-poison __VA_ARGS__
- This will also be used for the forthcoming __VA_OPT__ feature approved for C++2a. - recommended by rsmith during his review of the __VA_OPT__ patch (https://reviews.llvm.org/D35782) llvm-svn: 308948
1 parent 6f7befd commit 6bf6791

File tree

3 files changed

+69
-13
lines changed

3 files changed

+69
-13
lines changed

clang/include/clang/Lex/Preprocessor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ enum MacroUse {
9696
/// know anything about preprocessor-level issues like the \#include stack,
9797
/// token expansion, etc.
9898
class Preprocessor {
99+
friend class VariadicMacroScopeGuard;
99100
std::shared_ptr<PreprocessorOptions> PPOpts;
100101
DiagnosticsEngine *Diags;
101102
LangOptions &LangOpts;
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//===- VariadicMacroSupport.h - scope-guards etc. -*- C++ -*---------------===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// This file defines support types to help with preprocessing variadic macro
11+
// (i.e. macros that use: ellipses __VA_ARGS__ ) definitions and
12+
// expansions.
13+
//
14+
//===----------------------------------------------------------------------===//
15+
16+
#ifndef LLVM_CLANG_LEX_VARIADICMACROSUPPORT_H
17+
#define LLVM_CLANG_LEX_VARIADICMACROSUPPORT_H
18+
19+
#include "clang/Lex/Preprocessor.h"
20+
21+
namespace clang {
22+
23+
/// An RAII class that tracks when the Preprocessor starts and stops lexing the
24+
/// definition of a (ISO C/C++) variadic macro. As an example, this is useful
25+
/// for unpoisoning and repoisoning certain identifiers (such as __VA_ARGS__)
26+
/// that are only allowed in this context. Also, being a friend of the
27+
/// Preprocessor class allows it to access PP's cached identifiers directly (as
28+
/// opposed to performing a lookup each time).
29+
class VariadicMacroScopeGuard {
30+
const Preprocessor &PP;
31+
IdentifierInfo &Ident__VA_ARGS__;
32+
33+
public:
34+
VariadicMacroScopeGuard(const Preprocessor &P)
35+
: PP(P), Ident__VA_ARGS__(*PP.Ident__VA_ARGS__) {
36+
assert(Ident__VA_ARGS__.isPoisoned() && "__VA_ARGS__ should be poisoned "
37+
"outside an ISO C/C++ variadic "
38+
"macro definition!");
39+
}
40+
41+
/// Client code should call this function just before the Preprocessor is
42+
/// about to Lex tokens from the definition of a variadic (ISO C/C++) macro.
43+
void enterScope() { Ident__VA_ARGS__.setIsPoisoned(false); }
44+
45+
/// Client code should call this function as soon as the Preprocessor has
46+
/// either completed lexing the macro's definition tokens, or an error occured
47+
/// and the context is being exited. This function is idempotent (might be
48+
/// explicitly called, and then reinvoked via the destructor).
49+
void exitScope() { Ident__VA_ARGS__.setIsPoisoned(true); }
50+
51+
~VariadicMacroScopeGuard() { exitScope(); }
52+
};
53+
54+
} // end namespace clang
55+
56+
#endif

clang/lib/Lex/PPDirectives.cpp

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "clang/Lex/PreprocessorOptions.h"
3434
#include "clang/Lex/PTHLexer.h"
3535
#include "clang/Lex/Token.h"
36+
#include "clang/Lex/VariadicMacroSupport.h"
3637
#include "llvm/ADT/ArrayRef.h"
3738
#include "llvm/ADT/SmallString.h"
3839
#include "llvm/ADT/SmallVector.h"
@@ -2290,6 +2291,10 @@ MacroInfo *Preprocessor::ReadOptionalMacroParameterListAndBody(
22902291
Token Tok;
22912292
LexUnexpandedToken(Tok);
22922293

2294+
// Used to un-poison and then re-poison identifiers of the __VA_ARGS__ ilk
2295+
// within their appropriate context.
2296+
VariadicMacroScopeGuard VariadicMacroScopeGuard(*this);
2297+
22932298
// If this is a function-like macro definition, parse the argument list,
22942299
// marking each of the identifiers as being used as macro arguments. Also,
22952300
// check other constraints on the first token of the macro body.
@@ -2314,14 +2319,14 @@ MacroInfo *Preprocessor::ReadOptionalMacroParameterListAndBody(
23142319
return nullptr;
23152320
}
23162321

2317-
// If this is a definition of a variadic C99 function-like macro, not using
2318-
// the GNU named varargs extension, enabled __VA_ARGS__.
2322+
// If this is a definition of an ISO C/C++ variadic function-like macro (not
2323+
// using the GNU named varargs extension) inform our variadic scope guard
2324+
// which un-poisons and re-poisons certain identifiers (e.g. __VA_ARGS__)
2325+
// allowed only within the definition of a variadic macro.
23192326

2320-
// "Poison" __VA_ARGS__, which can only appear in the expansion of a macro.
2321-
// This gets unpoisoned where it is allowed.
2322-
assert(Ident__VA_ARGS__->isPoisoned() && "__VA_ARGS__ should be poisoned!");
2323-
if (MI->isC99Varargs())
2324-
Ident__VA_ARGS__->setIsPoisoned(false);
2327+
if (MI->isC99Varargs()) {
2328+
VariadicMacroScopeGuard.enterScope();
2329+
}
23252330

23262331
// Read the first token after the arg list for down below.
23272332
LexUnexpandedToken(Tok);
@@ -2431,9 +2436,6 @@ MacroInfo *Preprocessor::ReadOptionalMacroParameterListAndBody(
24312436
} else {
24322437
Diag(Tok, diag::err_pp_stringize_not_parameter)
24332438
<< LastTok.is(tok::hashat);
2434-
2435-
// Disable __VA_ARGS__ again.
2436-
Ident__VA_ARGS__->setIsPoisoned(true);
24372439
return nullptr;
24382440
}
24392441
}
@@ -2448,9 +2450,6 @@ MacroInfo *Preprocessor::ReadOptionalMacroParameterListAndBody(
24482450
}
24492451
}
24502452
MI->setDefinitionEndLoc(LastTok.getLocation());
2451-
// Disable __VA_ARGS__ again.
2452-
Ident__VA_ARGS__->setIsPoisoned(true);
2453-
24542453
return MI;
24552454
}
24562455
/// HandleDefineDirective - Implements \#define. This consumes the entire macro

0 commit comments

Comments
 (0)