From b384460fc34b2d2134efc649f3ac087126533ba9 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Thu, 19 May 2016 23:44:02 +0000 Subject: [PATCH] [Lexer] Don't merge macro args from different macro files The lexer sets the end location of macro arguments incorrectly *if*, while merging consecutive args to fit into a single SLocEntry, it finds args which come from different macro files. Fix the issue by using separate SLocEntries in this situation. This fixes a code coverage crasher (rdar://problem/26181005). Because the lexer reported end locations for certain macro args incorrectly, we would generate bogus coverage mappings with negative line offsets. Reviewed-by: akyrtzi Differential Revision: http://reviews.llvm.org/D20401 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@270160 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Lex/TokenLexer.cpp | 3 +++ test/CoverageMapping/Inputs/macros.h | 13 +++++++++++++ test/CoverageMapping/include-macros.c | 18 ++++++++++++++++++ unittests/Lex/LexerTest.cpp | 26 ++++++++++++++++++++++++-- 4 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 test/CoverageMapping/Inputs/macros.h create mode 100644 test/CoverageMapping/include-macros.c diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp index 478254dcd8..7f3be700c6 100644 --- a/lib/Lex/TokenLexer.cpp +++ b/lib/Lex/TokenLexer.cpp @@ -787,6 +787,9 @@ static void updateConsecutiveMacroArgTokens(SourceManager &SM, if (CurLoc.isFileID() != NextLoc.isFileID()) break; // Token from different kind of FileID. + if (CurLoc.isMacroID() && !SM.isWrittenInSameFile(CurLoc, NextLoc)) + break; // Token from a different macro. + int RelOffs; if (!SM.isInSameSLocAddrSpace(CurLoc, NextLoc, &RelOffs)) break; // Token from different local/loaded location. diff --git a/test/CoverageMapping/Inputs/macros.h b/test/CoverageMapping/Inputs/macros.h new file mode 100644 index 0000000000..0a2dadd1b8 --- /dev/null +++ b/test/CoverageMapping/Inputs/macros.h @@ -0,0 +1,13 @@ +// Assorted macros to help test #include behavior across file boundaries. + +#define helper1 0 + +void helper2(const char *, ...); + +#define M1(a, ...) helper2(a, ##__VA_ARGS__); + +// Note: M2 stresses vararg macro functions with macro arguments. The spelling +// locations of the args used to be set to the expansion site, leading to +// crashes (region LineEnd < LineStart). The regression test requires M2's line +// number to be greater than the line number containing the expansion. +#define M2(a, ...) M1(a, helper1, ##__VA_ARGS__); diff --git a/test/CoverageMapping/include-macros.c b/test/CoverageMapping/include-macros.c new file mode 100644 index 0000000000..113721c21a --- /dev/null +++ b/test/CoverageMapping/include-macros.c @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name include-macros.c %s | FileCheck %s + +#include "Inputs/macros.h" + +void f1() { + M2("a", "b"); +} + +// CHECK-LABEL: f1: +// CHECK-NEXT: File 0, 5:11 -> 7:2 = #0 +// CHECK-NEXT: Expansion,File 0, 6:3 -> 6:5 = #0 (Expanded file = 1) +// CHECK-NEXT: File 1, 13:20 -> 13:50 = #0 +// CHECK-NEXT: Expansion,File 1, 13:20 -> 13:22 = #0 (Expanded file = 2) +// CHECK-NEXT: File 2, 7:20 -> 7:46 = #0 +// CHECK-NEXT: Expansion,File 2, 7:33 -> 7:44 = #0 (Expanded file = 3) +// CHECK-NEXT: File 3, 13:26 -> 13:34 = #0 +// CHECK-NEXT: Expansion,File 3, 13:26 -> 13:33 = #0 (Expanded file = 4) +// CHECK-NEXT: File 4, 3:17 -> 3:18 = #0 diff --git a/unittests/Lex/LexerTest.cpp b/unittests/Lex/LexerTest.cpp index 0848f7b057..2046018181 100644 --- a/unittests/Lex/LexerTest.cpp +++ b/unittests/Lex/LexerTest.cpp @@ -58,8 +58,7 @@ protected: Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts); } - std::vector CheckLex(StringRef Source, - ArrayRef ExpectedTokens) { + std::vector Lex(StringRef Source) { std::unique_ptr Buf = llvm::MemoryBuffer::getMemBuffer(Source); SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf))); @@ -82,6 +81,12 @@ protected: toks.push_back(tok); } + return toks; + } + + std::vector CheckLex(StringRef Source, + ArrayRef ExpectedTokens) { + auto toks = Lex(Source); EXPECT_EQ(ExpectedTokens.size(), toks.size()); for (unsigned i = 0, e = ExpectedTokens.size(); i != e; ++i) { EXPECT_EQ(ExpectedTokens[i], toks[i].getKind()); @@ -358,4 +363,21 @@ TEST_F(LexerTest, LexAPI) { EXPECT_EQ("N", Lexer::getImmediateMacroName(idLoc4, SourceMgr, LangOpts)); } +TEST_F(LexerTest, DontMergeMacroArgsFromDifferentMacroFiles) { + std::vector toks = + Lex("#define helper1 0\n" + "void helper2(const char *, ...);\n" + "#define M1(a, ...) helper2(a, ##__VA_ARGS__)\n" + "#define M2(a, ...) M1(a, helper1, ##__VA_ARGS__)\n" + "void f1() { M2(\"a\", \"b\"); }"); + + // Check the file corresponding to the "helper1" macro arg in M2. + // + // The lexer used to report its size as 31, meaning that the end of the + // expansion would be on the *next line* (just past `M2("a", "b")`). Make + // sure that we get the correct end location (the comma after "helper1"). + SourceLocation helper1ArgLoc = toks[20].getLocation(); + EXPECT_EQ(SourceMgr.getFileIDSize(SourceMgr.getFileID(helper1ArgLoc)), 8U); +} + } // anonymous namespace -- 2.40.0