summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Foley <tfoley@nvidia.com>2017-06-19 14:21:14 -0700
committerTim Foley <tfoley@nvidia.com>2017-06-19 14:25:17 -0700
commit19906b6501a1d5b35d2bd26817ca724c9528b8d2 (patch)
tree6648c6f5b308aa60c461a9e894406914660885ed
parent838e8331da24744948539c12d2a8edcd9c594ee5 (diff)
Fixes for preprocessor conditionals that use macros
The basic underlying problem here is that the preprocessor tries to linger at the end of an input stream until it is sure it is time to advance. An input stream can include raw input files, or the expansion of a macro or macro argument. This was originally done to deal with not getting good end-of-line tokens when in directives (that issue has been fixed), but it is now a legacy issue that should probably be removed (but I am wary of making such a sweeping change). The problem that arises is that some code depends on what the actual input stream is (e.g., when turning conditionals on/off), and so we need to be careful. The bugs that this change affects arise when a `#if` or `#elseif` conditional expression *ends* with a macro expansion: #define FOO 2 #if 2 == FOO ... #endif When we try to start the preprocessor conditional block the "active" stream is still the expansion of `FOO`, when we needed it to be the input file. We fix this for now by snapshotting the input stream at the start of the directive, but a better long term fix would be to fix up this weird end-of-input behavior.
-rw-r--r--source/slang/preprocessor.cpp33
1 files changed, 25 insertions, 8 deletions
diff --git a/source/slang/preprocessor.cpp b/source/slang/preprocessor.cpp
index 6e0906d9e..00abb3fe5 100644
--- a/source/slang/preprocessor.cpp
+++ b/source/slang/preprocessor.cpp
@@ -1008,10 +1008,12 @@ static void DestroyConditional(PreprocessorConditional* conditional)
}
// Start a preprocessor conditional, with an initial enable/disable state.
-static void BeginConditional(PreprocessorDirectiveContext* context, bool enable)
+static void beginConditional(
+ PreprocessorDirectiveContext* context,
+ PreprocessorInputStream* inputStream,
+ bool enable)
{
Preprocessor* preprocessor = context->preprocessor;
- PreprocessorInputStream* inputStream = preprocessor->inputStream;
assert(inputStream);
PreprocessorConditional* conditional = CreateConditional(preprocessor);
@@ -1043,6 +1045,14 @@ static void BeginConditional(PreprocessorDirectiveContext* context, bool enable)
inputStream->conditional = conditional;
}
+// Start a preprocessor conditional, with an initial enable/disable state.
+static void beginConditional(
+ PreprocessorDirectiveContext* context,
+ bool enable)
+{
+ beginConditional(context, context->preprocessor->inputStream, enable);
+}
+
//
// Preprocessor Conditional Expressions
//
@@ -1302,11 +1312,16 @@ static PreprocessorExpressionValue ParseAndEvaluateExpression(PreprocessorDirect
// Handle a `#if` directive
static void HandleIfDirective(PreprocessorDirectiveContext* context)
{
+ // Record current inpu stream in case preprocessor expression
+ // changes the input stream to a macro expansion while we
+ // are parsing.
+ auto inputStream = context->preprocessor->inputStream;
+
// Parse a preprocessor expression.
PreprocessorExpressionValue value = ParseAndEvaluateExpression(context);
// Begin a preprocessor block, enabled based on the expression.
- BeginConditional(context, value != 0);
+ beginConditional(context, inputStream, value != 0);
}
// Handle a `#ifdef` directive
@@ -1319,7 +1334,7 @@ static void HandleIfDefDirective(PreprocessorDirectiveContext* context)
String name = nameToken.Content;
// Check if the name is defined.
- BeginConditional(context, LookupMacro(context, name) != NULL);
+ beginConditional(context, LookupMacro(context, name) != NULL);
}
// Handle a `#ifndef` directive
@@ -1332,7 +1347,7 @@ static void HandleIfNDefDirective(PreprocessorDirectiveContext* context)
String name = nameToken.Content;
// Check if the name is defined.
- BeginConditional(context, LookupMacro(context, name) == NULL);
+ beginConditional(context, LookupMacro(context, name) == NULL);
}
// Handle a `#else` directive
@@ -1376,6 +1391,11 @@ static void HandleElseDirective(PreprocessorDirectiveContext* context)
// Handle a `#elif` directive
static void HandleElifDirective(PreprocessorDirectiveContext* context)
{
+ // Need to grab current input stream *before* we try to parse
+ // the conditional expression.
+ PreprocessorInputStream* inputStream = context->preprocessor->inputStream;
+ assert(inputStream);
+
// HACK(tfoley): handle an empty `elif` like an `else` directive
//
// This is the behavior expected by at least one input program.
@@ -1390,9 +1410,6 @@ static void HandleElifDirective(PreprocessorDirectiveContext* context)
PreprocessorExpressionValue value = ParseAndEvaluateExpression(context);
- PreprocessorInputStream* inputStream = context->preprocessor->inputStream;
- assert(inputStream);
-
// if we aren't inside a conditional, then error
PreprocessorConditional* conditional = inputStream->conditional;
if (!conditional)