summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/Lex/PPDirectives.cpp14
-rw-r--r--clang/test/Preprocessor/stringize_skipped.c5
-rw-r--r--clang/unittests/Tooling/Syntax/TokensTest.cpp15
3 files changed, 29 insertions, 5 deletions
diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp
index 2756042f23e..5658f46c99d 100644
--- a/clang/lib/Lex/PPDirectives.cpp
+++ b/clang/lib/Lex/PPDirectives.cpp
@@ -33,6 +33,7 @@
#include "clang/Lex/Token.h"
#include "clang/Lex/VariadicMacroSupport.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/STLExtras.h"
@@ -2399,6 +2400,13 @@ MacroInfo *Preprocessor::ReadOptionalMacroParameterListAndBody(
Token Tok;
LexUnexpandedToken(Tok);
+ // Ensure we consume the rest of the macro body if errors occur.
+ auto _ = llvm::make_scope_exit([&]() {
+ // The flag indicates if we are still waiting for 'eod'.
+ if (CurLexer->ParsingPreprocessorDirective)
+ DiscardUntilEndOfDirective();
+ });
+
// Used to un-poison and then re-poison identifiers of the __VA_ARGS__ ilk
// within their appropriate context.
VariadicMacroScopeGuard VariadicMacroScopeGuard(*this);
@@ -2420,12 +2428,8 @@ MacroInfo *Preprocessor::ReadOptionalMacroParameterListAndBody(
} else if (Tok.is(tok::l_paren)) {
// This is a function-like macro definition. Read the argument list.
MI->setIsFunctionLike();
- if (ReadMacroParameterList(MI, LastTok)) {
- // Throw away the rest of the line.
- if (CurPPLexer->ParsingPreprocessorDirective)
- DiscardUntilEndOfDirective();
+ if (ReadMacroParameterList(MI, LastTok))
return nullptr;
- }
// 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
diff --git a/clang/test/Preprocessor/stringize_skipped.c b/clang/test/Preprocessor/stringize_skipped.c
new file mode 100644
index 00000000000..e9395fbbb4b
--- /dev/null
+++ b/clang/test/Preprocessor/stringize_skipped.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// Ensure we see the error from PP and do not see errors from the parser.
+
+// expected-error@+1{{'#' is not followed by a macro parameter}}
+#define INVALID() #B 10+10
diff --git a/clang/unittests/Tooling/Syntax/TokensTest.cpp b/clang/unittests/Tooling/Syntax/TokensTest.cpp
index 24adba28a29..a1398bd5568 100644
--- a/clang/unittests/Tooling/Syntax/TokensTest.cpp
+++ b/clang/unittests/Tooling/Syntax/TokensTest.cpp
@@ -298,6 +298,21 @@ file './input.cpp'
spelled tokens:
<empty>
no mappings.
+)"},
+ // Should not crash on errors inside '#define' directives. Error is that
+ // stringification (#B) does not refer to a macro parameter.
+ {
+ R"cpp(
+a
+#define MACRO() A #B
+)cpp",
+ R"(expanded tokens:
+ a
+file './input.cpp'
+ spelled tokens:
+ a # define MACRO ( ) A # B
+ mappings:
+ ['#'_1, '<eof>'_9) => ['<eof>'_1, '<eof>'_1)
)"}};
for (auto &Test : TestCases)
EXPECT_EQ(collectAndDump(Test.first), Test.second)
OpenPOWER on IntegriCloud