]> granicus.if.org Git - clang/commitdiff
[NFC] Use RAII to un-poison and then re-poison __VA_ARGS__
authorFaisal Vali <faisalv@yahoo.com>
Tue, 25 Jul 2017 03:15:36 +0000 (03:15 +0000)
committerFaisal Vali <faisalv@yahoo.com>
Tue, 25 Jul 2017 03:15:36 +0000 (03:15 +0000)
  - 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)

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@308948 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Lex/Preprocessor.h
include/clang/Lex/VariadicMacroSupport.h [new file with mode: 0644]
lib/Lex/PPDirectives.cpp

index a058fbfbb4cf7e0b3de739f06ad900cca9322912..49a95986fd64c53fa3078080f5fa6b9a261b86a8 100644 (file)
@@ -96,6 +96,7 @@ enum MacroUse {
 /// know anything about preprocessor-level issues like the \#include stack,
 /// token expansion, etc.
 class Preprocessor {
+  friend class VariadicMacroScopeGuard;
   std::shared_ptr<PreprocessorOptions> PPOpts;
   DiagnosticsEngine        *Diags;
   LangOptions       &LangOpts;
diff --git a/include/clang/Lex/VariadicMacroSupport.h b/include/clang/Lex/VariadicMacroSupport.h
new file mode 100644 (file)
index 0000000..dd36e39
--- /dev/null
@@ -0,0 +1,56 @@
+//===- VariadicMacroSupport.h - scope-guards etc. -*- C++ -*---------------===//\r
+//\r
+//                     The LLVM Compiler Infrastructure\r
+//\r
+// This file is distributed under the University of Illinois Open Source\r
+// License. See LICENSE.TXT for details.\r
+//\r
+//===----------------------------------------------------------------------===//\r
+//\r
+// This file defines support types to help with preprocessing variadic macro \r
+// (i.e. macros that use: ellipses __VA_ARGS__ ) definitions and \r
+// expansions.\r
+//\r
+//===----------------------------------------------------------------------===//\r
+\r
+#ifndef LLVM_CLANG_LEX_VARIADICMACROSUPPORT_H\r
+#define LLVM_CLANG_LEX_VARIADICMACROSUPPORT_H\r
+\r
+#include "clang/Lex/Preprocessor.h"\r
+\r
+namespace clang {\r
+\r
+/// An RAII class that tracks when the Preprocessor starts and stops lexing the\r
+/// definition of a (ISO C/C++) variadic macro.  As an example, this is useful\r
+/// for unpoisoning and repoisoning certain identifiers (such as __VA_ARGS__)\r
+/// that are only allowed in this context.  Also, being a friend of the\r
+/// Preprocessor class allows it to access PP's cached identifiers directly (as\r
+/// opposed to performing a lookup each time).\r
+class VariadicMacroScopeGuard {\r
+  const Preprocessor &PP;\r
+  IdentifierInfo &Ident__VA_ARGS__;\r
+\r
+public:\r
+  VariadicMacroScopeGuard(const Preprocessor &P)\r
+      : PP(P), Ident__VA_ARGS__(*PP.Ident__VA_ARGS__) {\r
+    assert(Ident__VA_ARGS__.isPoisoned() && "__VA_ARGS__ should be poisoned "\r
+                                            "outside an ISO C/C++ variadic "\r
+                                            "macro definition!");\r
+  }\r
+\r
+  /// Client code should call this function just before the Preprocessor is\r
+  /// about to Lex tokens from the definition of a variadic (ISO C/C++) macro.\r
+  void enterScope() { Ident__VA_ARGS__.setIsPoisoned(false); }\r
+\r
+  /// Client code should call this function as soon as the Preprocessor has\r
+  /// either completed lexing the macro's definition tokens, or an error occured\r
+  /// and the context is being exited.  This function is idempotent (might be\r
+  /// explicitly called, and then reinvoked via the destructor).\r
+  void exitScope() { Ident__VA_ARGS__.setIsPoisoned(true); }\r
+  \r
+  ~VariadicMacroScopeGuard() { exitScope(); }\r
+};\r
+\r
+}  // end namespace clang\r
+\r
+#endif\r
index b2450f516ba2a2774afe4d9ce66e6e5b5e299f3e..6b09398e468dcbc82cafa35c7b7a3b840d97e8a6 100644 (file)
@@ -33,6 +33,7 @@
 #include "clang/Lex/PreprocessorOptions.h"
 #include "clang/Lex/PTHLexer.h"
 #include "clang/Lex/Token.h"
+#include "clang/Lex/VariadicMacroSupport.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/SmallVector.h"
@@ -2290,6 +2291,10 @@ MacroInfo *Preprocessor::ReadOptionalMacroParameterListAndBody(
   Token Tok;
   LexUnexpandedToken(Tok);
 
+  // Used to un-poison and then re-poison identifiers of the __VA_ARGS__ ilk
+  // within their appropriate context.
+  VariadicMacroScopeGuard VariadicMacroScopeGuard(*this);
+
   // If this is a function-like macro definition, parse the argument list,
   // marking each of the identifiers as being used as macro arguments.  Also,
   // check other constraints on the first token of the macro body.
@@ -2314,14 +2319,14 @@ MacroInfo *Preprocessor::ReadOptionalMacroParameterListAndBody(
       return nullptr;
     }
 
-    // If this is a definition of a variadic C99 function-like macro, not using
-    // the GNU named varargs extension, enabled __VA_ARGS__.
+    // If this is a definition of an ISO C/C++ variadic function-like macro (not
+    // using the GNU named varargs extension) inform our variadic scope guard
+    // which un-poisons and re-poisons certain identifiers (e.g. __VA_ARGS__)
+    // allowed only within the definition of a variadic macro.
 
-    // "Poison" __VA_ARGS__, which can only appear in the expansion of a macro.
-    // This gets unpoisoned where it is allowed.
-    assert(Ident__VA_ARGS__->isPoisoned() && "__VA_ARGS__ should be poisoned!");
-    if (MI->isC99Varargs())
-      Ident__VA_ARGS__->setIsPoisoned(false);
+    if (MI->isC99Varargs()) {
+      VariadicMacroScopeGuard.enterScope();
+    }
 
     // Read the first token after the arg list for down below.
     LexUnexpandedToken(Tok);
@@ -2431,9 +2436,6 @@ MacroInfo *Preprocessor::ReadOptionalMacroParameterListAndBody(
         } else {
           Diag(Tok, diag::err_pp_stringize_not_parameter)
             << LastTok.is(tok::hashat);
-
-          // Disable __VA_ARGS__ again.
-          Ident__VA_ARGS__->setIsPoisoned(true);
           return nullptr;
         }
       }
@@ -2448,9 +2450,6 @@ MacroInfo *Preprocessor::ReadOptionalMacroParameterListAndBody(
     }
   }
   MI->setDefinitionEndLoc(LastTok.getLocation());
-  // Disable __VA_ARGS__ again.
-  Ident__VA_ARGS__->setIsPoisoned(true);
-
   return MI;
 }
 /// HandleDefineDirective - Implements \#define.  This consumes the entire macro