summaryrefslogtreecommitdiffstats
path: root/clang/lib/Frontend/DiagnosticRenderer.cpp
diff options
context:
space:
mode:
authorReid Kleckner <rnk@google.com>2015-12-08 01:08:09 +0000
committerReid Kleckner <rnk@google.com>2015-12-08 01:08:09 +0000
commitda30cff9ef2e22cf9e8e307f132976a15feacdf8 (patch)
treee4eca8e8c158a19eef3fe36b328e0123b16041db /clang/lib/Frontend/DiagnosticRenderer.cpp
parente6b36cdd4d571c91081e2d5f8c0b31830093d110 (diff)
downloadbcm5719-llvm-da30cff9ef2e22cf9e8e307f132976a15feacdf8.tar.gz
bcm5719-llvm-da30cff9ef2e22cf9e8e307f132976a15feacdf8.zip
[diagnostics] Avoid crashes while printing macro backtraces
When attempting to map a source into a given level of macro expansion, this code was ignoring the possibility that the start and end of the range might take wildly different paths through the tree of macro expansions. It was assuming that the begin spelling location would always precede the end spelling location, which is false. A macro can easily transpose its arguments. This also fixes a related issue where there are extra macro arguments between the begin location and the end location. In this situation, we now highlight the entire macro invocation. Pair programmed with Richard Smith. Fixes PR12818. llvm-svn: 254981
Diffstat (limited to 'clang/lib/Frontend/DiagnosticRenderer.cpp')
-rw-r--r--clang/lib/Frontend/DiagnosticRenderer.cpp83
1 files changed, 64 insertions, 19 deletions
diff --git a/clang/lib/Frontend/DiagnosticRenderer.cpp b/clang/lib/Frontend/DiagnosticRenderer.cpp
index 6ef9a89d86f..caf1f0dce99 100644
--- a/clang/lib/Frontend/DiagnosticRenderer.cpp
+++ b/clang/lib/Frontend/DiagnosticRenderer.cpp
@@ -308,34 +308,77 @@ void DiagnosticRenderer::emitModuleBuildStack(const SourceManager &SM) {
/// A recursive function to trace all possible backtrace locations
/// to match the \p CaretLocFileID.
-static SourceLocation retrieveMacroLocation(SourceLocation Loc,
- FileID MacroFileID,
- FileID CaretFileID,
- bool getBeginLoc,
- const SourceManager *SM) {
- if (MacroFileID == CaretFileID) return Loc;
- if (!Loc.isMacroID()) return SourceLocation();
+static SourceLocation
+retrieveMacroLocation(SourceLocation Loc, FileID MacroFileID,
+ FileID CaretFileID,
+ const SmallVectorImpl<FileID> &CommonArgExpansions,
+ bool IsBegin, const SourceManager *SM) {
+ assert(SM->getFileID(Loc) == MacroFileID);
+ if (MacroFileID == CaretFileID)
+ return Loc;
+ if (!Loc.isMacroID())
+ return SourceLocation();
SourceLocation MacroLocation, MacroArgLocation;
if (SM->isMacroArgExpansion(Loc)) {
- MacroLocation = SM->getImmediateSpellingLoc(Loc);
- MacroArgLocation = getBeginLoc ? SM->getImmediateExpansionRange(Loc).first
- : SM->getImmediateExpansionRange(Loc).second;
+ // Only look at the immediate spelling location of this macro argument if
+ // the other location in the source range is also present in that expansion.
+ if (std::binary_search(CommonArgExpansions.begin(),
+ CommonArgExpansions.end(), MacroFileID))
+ MacroLocation = SM->getImmediateSpellingLoc(Loc);
+ MacroArgLocation = IsBegin ? SM->getImmediateExpansionRange(Loc).first
+ : SM->getImmediateExpansionRange(Loc).second;
} else {
- MacroLocation = getBeginLoc ? SM->getImmediateExpansionRange(Loc).first
- : SM->getImmediateExpansionRange(Loc).second;
+ MacroLocation = IsBegin ? SM->getImmediateExpansionRange(Loc).first
+ : SM->getImmediateExpansionRange(Loc).second;
MacroArgLocation = SM->getImmediateSpellingLoc(Loc);
}
- MacroFileID = SM->getFileID(MacroLocation);
- MacroLocation = retrieveMacroLocation(MacroLocation, MacroFileID, CaretFileID,
- getBeginLoc, SM);
- if (MacroLocation.isValid()) return MacroLocation;
+ if (MacroLocation.isValid()) {
+ MacroFileID = SM->getFileID(MacroLocation);
+ MacroLocation =
+ retrieveMacroLocation(MacroLocation, MacroFileID, CaretFileID,
+ CommonArgExpansions, IsBegin, SM);
+ if (MacroLocation.isValid())
+ return MacroLocation;
+ }
MacroFileID = SM->getFileID(MacroArgLocation);
return retrieveMacroLocation(MacroArgLocation, MacroFileID, CaretFileID,
- getBeginLoc, SM);
+ CommonArgExpansions, IsBegin, SM);
+}
+
+/// Walk up the chain of macro expansions and collect the FileIDs identifying the
+/// expansions.
+static void getMacroArgExpansionFileIDs(SourceLocation Loc,
+ SmallVectorImpl<FileID> &IDs,
+ bool IsBegin, const SourceManager *SM) {
+ while (Loc.isMacroID()) {
+ if (SM->isMacroArgExpansion(Loc)) {
+ IDs.push_back(SM->getFileID(Loc));
+ Loc = SM->getImmediateSpellingLoc(Loc);
+ } else {
+ auto ExpRange = SM->getImmediateExpansionRange(Loc);
+ Loc = IsBegin ? ExpRange.first : ExpRange.second;
+ }
+ }
+}
+
+/// Collect the expansions of the begin and end locations and compute the set
+/// intersection. Produces a sorted vector of FileIDs in CommonArgExpansions.
+static void computeCommonMacroArgExpansionFileIDs(
+ SourceLocation Begin, SourceLocation End, const SourceManager *SM,
+ SmallVectorImpl<FileID> &CommonArgExpansions) {
+ SmallVector<FileID, 4> BeginArgExpansions;
+ SmallVector<FileID, 4> EndArgExpansions;
+ getMacroArgExpansionFileIDs(Begin, BeginArgExpansions, /*IsBegin=*/true, SM);
+ getMacroArgExpansionFileIDs(End, EndArgExpansions, /*IsBegin=*/false, SM);
+ std::sort(BeginArgExpansions.begin(), BeginArgExpansions.end());
+ std::sort(EndArgExpansions.begin(), EndArgExpansions.end());
+ std::set_intersection(BeginArgExpansions.begin(), BeginArgExpansions.end(),
+ EndArgExpansions.begin(), EndArgExpansions.end(),
+ std::back_inserter(CommonArgExpansions));
}
// Helper function to fix up source ranges. It takes in an array of ranges,
@@ -387,10 +430,12 @@ static void mapDiagnosticRanges(
}
// Do the backtracking.
+ SmallVector<FileID, 4> CommonArgExpansions;
+ computeCommonMacroArgExpansionFileIDs(Begin, End, SM, CommonArgExpansions);
Begin = retrieveMacroLocation(Begin, BeginFileID, CaretLocFileID,
- true /*getBeginLoc*/, SM);
+ CommonArgExpansions, /*IsBegin=*/true, SM);
End = retrieveMacroLocation(End, BeginFileID, CaretLocFileID,
- false /*getBeginLoc*/, SM);
+ CommonArgExpansions, /*IsBegin=*/false, SM);
if (Begin.isInvalid() || End.isInvalid()) continue;
// Return the spelling location of the beginning and end of the range.
OpenPOWER on IntegriCloud