Skip to content

Commit 09fe4ff

Browse files
Preprocessor bug (#9495)
Close #9494. The root cause of this issue is that we won't add "start of line" flag to the first token that is in the macro define, which makes sense because the macro could be expanded at any location. But we can make exception that if this macro is invoked at the start of line, we can safely mark the first token as "start of the line". --------- Co-authored-by: Ellie Hermaszewska <ellieh@nvidia.com>
1 parent 528ddf7 commit 09fe4ff

File tree

2 files changed

+42
-4
lines changed

2 files changed

+42
-4
lines changed

source/slang/slang-preprocessor.cpp

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -703,7 +703,8 @@ struct MacroInvocation : InputStream
703703
Preprocessor* preprocessor,
704704
MacroDefinition* macro,
705705
SourceLoc macroInvocationLoc,
706-
SourceLoc initiatingMacroInvocationLoc);
706+
SourceLoc initiatingMacroInvocationLoc,
707+
bool isStartOfLine = false);
707708

708709
/// Prime the input stream
709710
///
@@ -809,6 +810,10 @@ struct MacroInvocation : InputStream
809810
/// by `valueBuilder`
810811
template<typename F>
811812
void _pushStreamForSourceLocBuiltin(TokenType tokenType, F const& valueBuilder);
813+
814+
/// Indicate that whether this invocation is at the start of a line, this can be determined by
815+
/// the macro invocation token.
816+
bool m_isStartOfLine = false;
812817
};
813818

814819
// Playing back macro bodies for macro invocations is one part of the expansion process, and the
@@ -1460,13 +1465,15 @@ MacroInvocation::MacroInvocation(
14601465
Preprocessor* preprocessor,
14611466
MacroDefinition* macro,
14621467
SourceLoc macroInvocationLoc,
1463-
SourceLoc initiatingMacroInvocationLoc)
1468+
SourceLoc initiatingMacroInvocationLoc,
1469+
bool isStartOfLine)
14641470
: Super(preprocessor)
14651471
{
14661472
m_macro = macro;
14671473
m_firstBusyMacroInvocation = this;
14681474
m_macroInvocationLoc = macroInvocationLoc;
14691475
m_initiatingMacroInvocationLoc = initiatingMacroInvocationLoc;
1476+
m_isStartOfLine = isStartOfLine;
14701477
}
14711478

14721479
void MacroInvocation::prime(MacroInvocation* nextBusyMacroInvocation)
@@ -1683,6 +1690,7 @@ void ExpansionInputStream::_maybeBeginMacroInvocation()
16831690
return;
16841691
}
16851692

1693+
bool isStartOfLine = (token.flags & TokenFlag::AtStartOfLine) != 0;
16861694
// Now we get to the slightly trickier cases.
16871695
//
16881696
// *If* the identifier names a macro, but we are currently in the
@@ -1749,7 +1757,8 @@ void ExpansionInputStream::_maybeBeginMacroInvocation()
17491757
preprocessor,
17501758
macro,
17511759
token.loc,
1752-
m_initiatingMacroInvocationLoc);
1760+
m_initiatingMacroInvocationLoc,
1761+
isStartOfLine);
17531762
invocation->prime(busyMacros);
17541763
_pushMacroInvocation(invocation);
17551764
}
@@ -1806,7 +1815,8 @@ void ExpansionInputStream::_maybeBeginMacroInvocation()
18061815
preprocessor,
18071816
macro,
18081817
token.loc,
1809-
m_initiatingMacroInvocationLoc);
1818+
m_initiatingMacroInvocationLoc,
1819+
isStartOfLine);
18101820

18111821
// We start by consuming the opening `(` that we checked for above.
18121822
//
@@ -1982,6 +1992,11 @@ Token MacroInvocation::_readTokenImpl()
19821992
// We can safely return with our invaraints intact, because
19831993
// the next attempt to read a token will read a non-EOF.
19841994
//
1995+
// Before returning, we need to check whether this macro invocation is
1996+
// at start of line, if it is, we must mark the first token as start of line
1997+
// as well, otherwise the expanded code could be invalid.
1998+
if (m_isStartOfLine)
1999+
token.flags |= TokenFlag::AtStartOfLine;
19852000
return token;
19862001
}
19872002

@@ -2003,7 +2018,14 @@ Token MacroInvocation::_readTokenImpl()
20032018
// end of the macro expansion.
20042019
//
20052020
if (nextOpIndex == m_macro->ops.getCount())
2021+
{
2022+
// Before returning, we need to check whether this macro invocation is
2023+
// at start of line, if it is, we must mark the first token as start of line
2024+
// as well, otherwise the expanded code could be invalid.
2025+
if (m_isStartOfLine)
2026+
token.flags |= TokenFlag::AtStartOfLine;
20062027
return token;
2028+
}
20072029

20082030
// Because `m_currentOpStreams` is at its end, we can pop all of
20092031
// those streams to reclaim their memory before we push any new
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//TEST:SIMPLE:
2+
// Test for issue: https://github.com/shader-slang/slang/issues/9494
3+
// It demonstrates that the macro invocation `Def` will start at a new line, otherwise the compilation
4+
// will fail due to the 'public' keyword being unexpected after the enum declaration
5+
enum TargetEnum
6+
{
7+
Target_1,
8+
}
9+
10+
#define Def \
11+
public struct TestStruct \
12+
{ \
13+
public static const int Value = 42; \
14+
} \
15+
16+
Def

0 commit comments

Comments
 (0)