]> granicus.if.org Git - clang/commitdiff
Make the Preprocessor more memory efficient and improve macro instantiation diagnostics.
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>
Thu, 7 Jul 2011 03:40:34 +0000 (03:40 +0000)
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>
Thu, 7 Jul 2011 03:40:34 +0000 (03:40 +0000)
When a macro instantiation occurs, reserve a SLocEntry chunk with length the
full length of the macro definition source. Set the spelling location of this chunk
to point to the start of the macro definition and any tokens that are lexed directly
from the macro definition will get a location from this chunk with the appropriate offset.

For any tokens that come from argument expansion, '##' paste operator, etc. have their
instantiation location point at the appropriate place in the instantiated macro definition
(the argument identifier and the '##' token respectively).
This improves macro instantiation diagnostics:

Before:

t.c:5:9: error: invalid operands to binary expression ('struct S' and 'int')
int y = M(/);
        ^~~~
t.c:5:11: note: instantiated from:
int y = M(/);
          ^

After:

t.c:5:9: error: invalid operands to binary expression ('struct S' and 'int')
int y = M(/);
        ^~~~
t.c:3:20: note: instantiated from:
\#define M(op) (foo op 3);
                ~~~ ^  ~
t.c:5:11: note: instantiated from:
int y = M(/);
          ^

The memory savings for a candidate boost library that abuses the preprocessor are:

- 32% less SLocEntries (37M -> 25M)
- 30% reduction in PCH file size (900M -> 635M)
- 50% reduction in memory usage for the SLocEntry table (1.6G -> 800M)

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@134587 91177308-0d34-0410-b5e6-96231b3b80d8

15 files changed:
include/clang/Basic/SourceManager.h
include/clang/Lex/MacroInfo.h
include/clang/Lex/TokenLexer.h
lib/ARCMigrate/TransformActions.cpp
lib/ARCMigrate/Transforms.cpp
lib/Basic/SourceManager.cpp
lib/Lex/Lexer.cpp
lib/Lex/MacroArgs.cpp
lib/Lex/MacroArgs.h
lib/Lex/MacroInfo.cpp
lib/Lex/TokenLexer.cpp
lib/Parse/ParseExpr.cpp
test/PCH/variables.c
test/PCH/variables.h
test/Parser/recovery.c

index 05551e5319f6425d2171aa260260bdd6e9c462a1..33c66e7f7c057b3f8a01fc727779a6f1dccb8a05 100644 (file)
@@ -36,6 +36,7 @@ class SourceManager;
 class FileManager;
 class FileEntry;
 class LineTableInfo;
+class LangOptions;
   
 /// SrcMgr - Public enums and private classes that are part of the
 /// SourceManager implementation.
@@ -833,11 +834,46 @@ public:
 
   /// \brief Returns true if the given MacroID location points at the first
   /// token of the macro instantiation.
-  bool isAtStartOfMacroInstantiation(SourceLocation Loc) const;
+  bool isAtStartOfMacroInstantiation(SourceLocation Loc,
+                                     const LangOptions &LangOpts) const;
 
   /// \brief Returns true if the given MacroID location points at the last
   /// token of the macro instantiation.
-  bool isAtEndOfMacroInstantiation(SourceLocation Loc) const;
+  bool isAtEndOfMacroInstantiation(SourceLocation Loc,
+                                   const LangOptions &LangOpts) const;
+
+  /// \brief Given a specific chunk of a FileID (FileID with offset+length),
+  /// returns true if \arg Loc is inside that chunk and sets relative offset
+  /// (offset of \arg Loc from beginning of chunk) to \arg relativeOffset.
+  bool isInFileID(SourceLocation Loc,
+                  FileID FID, unsigned offset, unsigned length,
+                  unsigned *relativeOffset = 0) const {
+    assert(!FID.isInvalid());
+    if (Loc.isInvalid())
+      return false;
+
+    unsigned start = getSLocEntry(FID).getOffset() + offset;
+    unsigned end = start + length;
+
+#ifndef NDEBUG
+    // Make sure offset/length describe a chunk inside the given FileID.
+    unsigned NextOffset;
+    if (FID.ID+1 == SLocEntryTable.size())
+      NextOffset = getNextOffset();
+    else
+      NextOffset = getSLocEntry(FID.ID+1).getOffset();
+    assert(start < NextOffset);
+    assert(end   < NextOffset);
+#endif
+
+    if (Loc.getOffset() >= start && Loc.getOffset() < end) {
+      if (relativeOffset)
+        *relativeOffset = Loc.getOffset() - start;
+      return true;
+    }
+
+    return false;
+  }
 
   //===--------------------------------------------------------------------===//
   // Line Table Manipulation Routines
@@ -899,6 +935,19 @@ public:
   /// \returns true if LHS source location comes before RHS, false otherwise.
   bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const;
 
+  /// \brief Determines the order of 2 source locations in the "source location
+  /// address space".
+  static bool isBeforeInSourceLocationOffset(SourceLocation LHS,
+                                             SourceLocation RHS) {
+    return isBeforeInSourceLocationOffset(LHS, RHS.getOffset());
+  }
+
+  /// \brief Determines the order of a source location and a source location
+  /// offset in the "source location address space".
+  static bool isBeforeInSourceLocationOffset(SourceLocation LHS, unsigned RHS) {
+    return LHS.getOffset() < RHS;
+  }
+
   // Iterators over FileInfos.
   typedef llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*>
       ::const_iterator fileinfo_iterator;
index 7c4cfb007233ee059cb050b9584d548e21cc12f5..9e9d7cf500a42c4ca8900c59cfc03244d059282b 100644 (file)
@@ -43,6 +43,10 @@ class MacroInfo {
   /// to.
   llvm::SmallVector<Token, 8> ReplacementTokens;
 
+  /// \brief Length in characters of the macro definition.
+  mutable unsigned DefinitionLength;
+  mutable bool IsDefinitionLengthCached : 1;
+
   /// IsFunctionLike - True if this macro is a function-like macro, false if it
   /// is an object-like macro.
   bool IsFunctionLike : 1;
@@ -116,6 +120,13 @@ public:
   /// getDefinitionEndLoc - Return the location of the last token in the macro.
   ///
   SourceLocation getDefinitionEndLoc() const { return EndLocation; }
+  
+  /// \brief Get length in characters of the macro definition.
+  unsigned getDefinitionLength(SourceManager &SM) const {
+    if (IsDefinitionLengthCached)
+      return DefinitionLength;
+    return getDefinitionLengthSlow(SM);
+  }
 
   /// isIdenticalTo - Return true if the specified macro definition is equal to
   /// this macro in spelling, arguments, and whitespace.  This is used to emit
@@ -232,6 +243,8 @@ public:
   /// AddTokenToBody - Add the specified token to the replacement text for the
   /// macro.
   void AddTokenToBody(const Token &Tok) {
+    assert(!IsDefinitionLengthCached &&
+          "Changing replacement tokens after definition length got calculated");
     ReplacementTokens.push_back(Tok);
   }
 
@@ -248,6 +261,9 @@ public:
     assert(!IsDisabled && "Cannot disable an already-disabled macro!");
     IsDisabled = true;
   }
+
+private:
+  unsigned getDefinitionLengthSlow(SourceManager &SM) const;
 };
 
 }  // end namespace clang
index 8f530053ca637116f066ed42c902f6a5e579e855..ea36e0e0e809067348998d4630f2dbc6a338fe09 100644 (file)
@@ -63,6 +63,17 @@ class TokenLexer {
   /// instantiated.
   SourceLocation InstantiateLocStart, InstantiateLocEnd;
 
+  /// \brief Source location pointing at the source location entry chunk that
+  /// was reserved for the current macro instantiation.
+  SourceLocation MacroExpansionStart;
+  
+  /// \brief The offset of the macro instantiation in the
+  /// "source location address space".
+  unsigned MacroStartSLocOffset;
+
+  /// \brief FileID/offset of the start of the macro definition.
+  std::pair<FileID, unsigned> MacroDefStartInfo;
+
   /// Lexical information about the expansion point of the macro: the identifier
   /// that the macro expanded from had these properties.
   bool AtStartOfLine : 1;
@@ -154,6 +165,11 @@ private:
   /// source line of the instantiated buffer.  Handle this by returning the
   /// first token on the next line.
   void HandleMicrosoftCommentPaste(Token &Tok);
+
+  /// \brief If \arg loc is a FileID and points inside the current macro
+  /// definition, returns the appropriate source location pointing at the
+  /// macro expansion source location entry.
+  SourceLocation getMacroExpansionLocation(SourceLocation loc) const;
 };
 
 }  // end namespace clang
index cd8a80e86b7028d4d27e5ab211365ffe7c3c5297..45a3d473e6008818c777e177772a3a0a0ed42f62 100644 (file)
@@ -388,7 +388,7 @@ bool TransformActionsImpl::canInsert(SourceLocation loc) {
 
   if (loc.isFileID())
     return true;
-  return SM.isAtStartOfMacroInstantiation(loc);
+  return SM.isAtStartOfMacroInstantiation(loc, Ctx.getLangOptions());
 }
 
 bool TransformActionsImpl::canInsertAfterToken(SourceLocation loc) {
@@ -401,7 +401,7 @@ bool TransformActionsImpl::canInsertAfterToken(SourceLocation loc) {
 
   if (loc.isFileID())
     return true;
-  return SM.isAtEndOfMacroInstantiation(loc);
+  return SM.isAtEndOfMacroInstantiation(loc, Ctx.getLangOptions());
 }
 
 bool TransformActionsImpl::canRemoveRange(SourceRange range) {
index 80445c70ac613c84f65deadc903459a9ac70658a..1a98833fe0870c2475e894b757c639aa119b2dd7 100644 (file)
@@ -37,7 +37,7 @@ SourceLocation trans::findLocationAfterSemi(SourceLocation loc,
                                             ASTContext &Ctx) {
   SourceManager &SM = Ctx.getSourceManager();
   if (loc.isMacroID()) {
-    if (!SM.isAtEndOfMacroInstantiation(loc))
+    if (!SM.isAtEndOfMacroInstantiation(loc, Ctx.getLangOptions()))
       return SourceLocation();
     loc = SM.getInstantiationRange(loc).second;
   }
index d6c4c16cec745157fab122f0b62aec1b5ff22112..137da0d87ada88ddbb662b91343b4a8289b88549 100644 (file)
@@ -11,6 +11,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "clang/Lex/Lexer.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Basic/SourceManagerInternals.h"
 #include "clang/Basic/Diagnostic.h"
@@ -1216,73 +1217,56 @@ PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const {
 
 /// \brief Returns true if the given MacroID location points at the first
 /// token of the macro instantiation.
-bool SourceManager::isAtStartOfMacroInstantiation(SourceLocation loc) const {
+bool SourceManager::isAtStartOfMacroInstantiation(SourceLocation loc,
+                                            const LangOptions &LangOpts) const {
   assert(loc.isValid() && loc.isMacroID() && "Expected a valid macro loc");
 
   std::pair<FileID, unsigned> infoLoc = getDecomposedLoc(loc);
+  // FIXME: If the token comes from the macro token paste operator ('##')
+  // this function will always return false;
   if (infoLoc.second > 0)
     return false; // Does not point at the start of token.
 
-  unsigned FID = infoLoc.first.ID;
-  assert(FID > 1);
-  std::pair<SourceLocation, SourceLocation>
-    instRange = getImmediateInstantiationRange(loc);
-
-  bool invalid = false;
-  const SrcMgr::SLocEntry &Entry = getSLocEntry(FID-1, &invalid);
-  if (invalid)
-    return false;
-
-  // If the FileID immediately before it is a file then this is the first token
-  // in the macro.
-  if (Entry.isFile())
-    return true;
+  SourceLocation instLoc = 
+      getSLocEntry(infoLoc.first).getInstantiation().getInstantiationLocStart();
+  if (instLoc.isFileID())
+    return true; // No other macro instantiations, this is the first.
 
-  // If the FileID immediately before it (which is a macro token) is the
-  // immediate instantiated macro, check this macro token's location.
-  if (getFileID(instRange.second).ID == FID-1)
-    return isAtStartOfMacroInstantiation(instRange.first);
-
-  // If the FileID immediately before it (which is a macro token) came from a
-  // different instantiation, then this is the first token in the macro.
-  if (getInstantiationLoc(Entry.getInstantiation().getInstantiationLocStart())
-        != getInstantiationLoc(loc))
-    return true;
-
-  // It is inside the macro or the last token in the macro.
-  return false;
+  return isAtStartOfMacroInstantiation(instLoc, LangOpts);
 }
 
 /// \brief Returns true if the given MacroID location points at the last
 /// token of the macro instantiation.
-bool SourceManager::isAtEndOfMacroInstantiation(SourceLocation loc) const {
+bool SourceManager::isAtEndOfMacroInstantiation(SourceLocation loc,
+                                            const LangOptions &LangOpts) const {
   assert(loc.isValid() && loc.isMacroID() && "Expected a valid macro loc");
 
-  unsigned FID = getFileID(loc).ID;
-  assert(FID > 1);
-  std::pair<SourceLocation, SourceLocation>
-    instRange = getInstantiationRange(loc);
+  SourceLocation spellLoc = getSpellingLoc(loc);
+  unsigned tokLen = Lexer::MeasureTokenLength(spellLoc, *this, LangOpts);
+  if (tokLen == 0)
+    return false;
+
+  std::pair<FileID, unsigned> infoLoc = getDecomposedLoc(loc);
+  unsigned FID = infoLoc.first.ID;
 
-  // If there's no FileID after it, it is the last token in the macro.
+  unsigned NextOffset;
   if (FID+1 == sloc_entry_size())
-    return true;
-
-  bool invalid = false;
-  const SrcMgr::SLocEntry &Entry = getSLocEntry(FID+1, &invalid);
-  if (invalid)
-    return false;
+    NextOffset = getNextOffset();
+  else
+    NextOffset = getSLocEntry(FID+1).getOffset();
 
-  // If the FileID immediately after it is a file or a macro token which
-  // came from a different instantiation, then this is the last token in the
-  // macro.
-  if (Entry.isFile())
-    return true;
-  if (getInstantiationLoc(Entry.getInstantiation().getInstantiationLocStart())
-        != instRange.first)
-    return true;
+  // FIXME: If the token comes from the macro token paste operator ('##')
+  // or the stringify operator ('#') this function will always return false;
+  assert(loc.getOffset() + tokLen < NextOffset);
+  if (loc.getOffset() + tokLen < NextOffset-1)
+    return false; // Does not point to the last token.
+  
+  SourceLocation instLoc = 
+      getSLocEntry(infoLoc.first).getInstantiation().getInstantiationLocEnd();
+  if (instLoc.isFileID())
+    return true; // No other macro instantiations.
 
-  // It is inside the macro or the first token in the macro.
-  return false;
+  return isAtEndOfMacroInstantiation(instLoc, LangOpts);
 }
 
 //===----------------------------------------------------------------------===//
@@ -1479,8 +1463,6 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS,
   // reflect the order that the tokens, pointed to by these locations, were
   // instantiated (during parsing each token that is instantiated by a macro,
   // expands the SLocEntries).
-  if (LHS.isMacroID() && RHS.isMacroID())
-    return LHS.getOffset() < RHS.getOffset();
 
   std::pair<FileID, unsigned> LOffs = getDecomposedLoc(LHS);
   std::pair<FileID, unsigned> ROffs = getDecomposedLoc(RHS);
index 608bd9d0c5cd80572c50a697c937239ad2ac46de..6d25d2b2cf52947e9bb9b0d9acc1605d8ac822eb 100644 (file)
@@ -683,7 +683,7 @@ SourceLocation Lexer::getLocForEndOfToken(SourceLocation Loc, unsigned Offset,
     return SourceLocation();
 
   if (Loc.isMacroID()) {
-    if (Offset > 0 || !SM.isAtEndOfMacroInstantiation(Loc))
+    if (Offset > 0 || !SM.isAtEndOfMacroInstantiation(Loc, Features))
       return SourceLocation(); // Points inside the macro instantiation.
 
     // Continue and find the location just after the macro instantiation.
index dee7da38aaa007a513b1490e03b7cc1a49ad48ad..968c15e3c27b59872da7c40cfee7e0a177ba74bf 100644 (file)
@@ -185,7 +185,8 @@ MacroArgs::getPreExpArgument(unsigned Arg, const MacroInfo *MI,
 /// a character literal for the Microsoft charize (#@) extension.
 ///
 Token MacroArgs::StringifyArgument(const Token *ArgToks,
-                                   Preprocessor &PP, bool Charify) {
+                                   Preprocessor &PP, bool Charify,
+                                   SourceLocation hashInstLoc) {
   Token Tok;
   Tok.startToken();
   Tok.setKind(Charify ? tok::char_constant : tok::string_literal);
@@ -273,14 +274,15 @@ Token MacroArgs::StringifyArgument(const Token *ArgToks,
     }
   }
 
-  PP.CreateString(&Result[0], Result.size(), Tok);
+  PP.CreateString(&Result[0], Result.size(), Tok, hashInstLoc);
   return Tok;
 }
 
 /// getStringifiedArgument - Compute, cache, and return the specified argument
 /// that has been 'stringified' as required by the # operator.
 const Token &MacroArgs::getStringifiedArgument(unsigned ArgNo,
-                                               Preprocessor &PP) {
+                                               Preprocessor &PP,
+                                               SourceLocation hashInstLoc) {
   assert(ArgNo < NumUnexpArgTokens && "Invalid argument number!");
   if (StringifiedArgs.empty()) {
     StringifiedArgs.resize(getNumArguments());
@@ -288,6 +290,7 @@ const Token &MacroArgs::getStringifiedArgument(unsigned ArgNo,
            sizeof(StringifiedArgs[0])*getNumArguments());
   }
   if (StringifiedArgs[ArgNo].isNot(tok::string_literal))
-    StringifiedArgs[ArgNo] = StringifyArgument(getUnexpArgument(ArgNo), PP);
+    StringifiedArgs[ArgNo] = StringifyArgument(getUnexpArgument(ArgNo), PP,
+                                               /*Charify=*/false, hashInstLoc);
   return StringifiedArgs[ArgNo];
 }
index 6ff4856b4e1c03183f618c2945427d80440544dc..a962dacf7c9300efbf81f5b5e59735e633e1b624 100644 (file)
@@ -20,6 +20,7 @@ namespace clang {
   class MacroInfo;
   class Preprocessor;
   class Token;
+  class SourceLocation;
 
 /// MacroArgs - An instance of this class captures information about
 /// the formal arguments specified to a function-like macro invocation.
@@ -86,7 +87,8 @@ public:
 
   /// getStringifiedArgument - Compute, cache, and return the specified argument
   /// that has been 'stringified' as required by the # operator.
-  const Token &getStringifiedArgument(unsigned ArgNo, Preprocessor &PP);
+  const Token &getStringifiedArgument(unsigned ArgNo, Preprocessor &PP,
+                                      SourceLocation hashInstLoc);
 
   /// getNumArguments - Return the number of arguments passed into this macro
   /// invocation.
@@ -106,7 +108,8 @@ public:
   /// a character literal for the Microsoft charize (#@) extension.
   ///
   static Token StringifyArgument(const Token *ArgToks,
-                                 Preprocessor &PP, bool Charify = false);
+                                 Preprocessor &PP, bool Charify,
+                                 SourceLocation hashInstLoc);
   
   
   /// deallocate - This should only be called by the Preprocessor when managing
index 66d87a19386a9df5948e8225fa9ab866c35f81b5..0a16a25672195f87a33ab18eab1821ca25afd385 100644 (file)
@@ -25,6 +25,7 @@ MacroInfo::MacroInfo(SourceLocation DefLoc) : Location(DefLoc) {
   IsUsed = false;
   IsAllowRedefinitionsWithoutWarning = false;
   IsWarnIfUnused = false;
+  IsDefinitionLengthCached = false;
 
   ArgumentList = 0;
   NumArguments = 0;
@@ -43,11 +44,42 @@ MacroInfo::MacroInfo(const MacroInfo &MI, llvm::BumpPtrAllocator &PPAllocator) {
   IsUsed = MI.IsUsed;
   IsAllowRedefinitionsWithoutWarning = MI.IsAllowRedefinitionsWithoutWarning;
   IsWarnIfUnused = MI.IsWarnIfUnused;
+  IsDefinitionLengthCached = MI.IsDefinitionLengthCached;
+  DefinitionLength = MI.DefinitionLength;
   ArgumentList = 0;
   NumArguments = 0;
   setArgumentList(MI.ArgumentList, MI.NumArguments, PPAllocator);
 }
 
+unsigned MacroInfo::getDefinitionLengthSlow(SourceManager &SM) const {
+  assert(!IsDefinitionLengthCached);
+  IsDefinitionLengthCached = true;
+
+  if (ReplacementTokens.empty())
+    return (DefinitionLength = 0);
+
+  const Token &firstToken = ReplacementTokens.front();
+  const Token &lastToken = ReplacementTokens.back();
+  SourceLocation macroStart = firstToken.getLocation();
+  SourceLocation macroEnd = lastToken.getLocation();
+  assert(macroStart.isValid() && macroEnd.isValid());
+  assert((macroStart.isFileID() || firstToken.is(tok::comment)) &&
+         "Macro defined in macro?");
+  assert((macroEnd.isFileID() || lastToken.is(tok::comment)) &&
+         "Macro defined in macro?");
+  std::pair<FileID, unsigned>
+      startInfo = SM.getDecomposedInstantiationLoc(macroStart);
+  std::pair<FileID, unsigned>
+      endInfo = SM.getDecomposedInstantiationLoc(macroEnd);
+  assert(startInfo.first == endInfo.first &&
+         "Macro definition spanning multiple FileIDs ?");
+  assert(startInfo.second <= endInfo.second);
+  DefinitionLength = endInfo.second - startInfo.second;
+  DefinitionLength += lastToken.getLength();
+
+  return DefinitionLength;
+}
+
 /// isIdenticalTo - Return true if the specified macro definition is equal to
 /// this macro in spelling, arguments, and whitespace.  This is used to emit
 /// duplicate definition warnings.  This implements the rules in C99 6.10.3.
index f30c44e0e64e7a6abecd903c943a834b5460e85e..db37fe15f384c0f599b0e219f37f58d8c4c80a2c 100644 (file)
@@ -40,6 +40,28 @@ void TokenLexer::Init(Token &Tok, SourceLocation ILEnd, MacroArgs *Actuals) {
   OwnsTokens = false;
   DisableMacroExpansion = false;
   NumTokens = Macro->tokens_end()-Macro->tokens_begin();
+  MacroExpansionStart = SourceLocation();
+
+  SourceManager &SM = PP.getSourceManager();
+  MacroStartSLocOffset = SM.getNextOffset();
+
+  if (NumTokens > 0) {
+    assert(Tokens[0].getLocation().isValid());
+    assert((Tokens[0].getLocation().isFileID() || Tokens[0].is(tok::comment)) &&
+           "Macro defined in macro?");
+    assert(InstantiateLocStart.isValid());
+
+    // Reserve a source location entry chunk for the length of the macro
+    // definition. Tokens that get lexed directly from the definition will
+    // have their locations pointing inside this chunk. This is to avoid
+    // creating separate source location entries for each token.
+    SourceLocation macroStart = SM.getInstantiationLoc(Tokens[0].getLocation());
+    MacroDefStartInfo = SM.getDecomposedLoc(macroStart);
+    MacroExpansionStart = SM.createInstantiationLoc(macroStart,
+                                              InstantiateLocStart,
+                                              InstantiateLocEnd,
+                                              Macro->getDefinitionLength(SM));
+  }
 
   // If this is a function-like macro, expand the arguments and change
   // Tokens to point to the expanded tokens.
@@ -72,6 +94,7 @@ void TokenLexer::Init(const Token *TokArray, unsigned NumToks,
   InstantiateLocStart = InstantiateLocEnd = SourceLocation();
   AtStartOfLine = false;
   HasLeadingSpace = false;
+  MacroExpansionStart = SourceLocation();
 
   // Set HasLeadingSpace/AtStartOfLine so that the first token will be
   // returned unmodified.
@@ -119,13 +142,19 @@ void TokenLexer::ExpandFunctionArguments() {
       int ArgNo = Macro->getArgumentNum(Tokens[i+1].getIdentifierInfo());
       assert(ArgNo != -1 && "Token following # is not an argument?");
 
+      SourceLocation hashInstLoc;
+      if(InstantiateLocStart.isValid()) {
+        hashInstLoc = getMacroExpansionLocation(CurTok.getLocation());
+        assert(hashInstLoc.isValid() && "Expected '#' to come from definition");
+      }
+
       Token Res;
       if (CurTok.is(tok::hash))  // Stringify
-        Res = ActualArgs->getStringifiedArgument(ArgNo, PP);
+        Res = ActualArgs->getStringifiedArgument(ArgNo, PP, hashInstLoc);
       else {
         // 'charify': don't bother caching these.
         Res = MacroArgs::StringifyArgument(ActualArgs->getUnexpArgument(ArgNo),
-                                           PP, true);
+                                           PP, true, hashInstLoc);
       }
 
       // The stringified/charified string leading space flag gets set to match
@@ -185,6 +214,20 @@ void TokenLexer::ExpandFunctionArguments() {
         unsigned NumToks = MacroArgs::getArgLength(ResultArgToks);
         ResultToks.append(ResultArgToks, ResultArgToks+NumToks);
 
+        if(InstantiateLocStart.isValid()) {
+          SourceManager &SM = PP.getSourceManager();
+          SourceLocation curInst =
+              getMacroExpansionLocation(CurTok.getLocation());
+          assert(curInst.isValid() &&
+                 "Expected arg identifier to come from definition");
+          for (unsigned i = FirstResult, e = ResultToks.size(); i != e; ++i) {
+            Token &Tok = ResultToks[i];
+            Tok.setLocation(SM.createInstantiationLoc(Tok.getLocation(),
+                                                      curInst, curInst,
+                                                      Tok.getLength()));
+          }
+        }
+
         // If any tokens were substituted from the argument, the whitespace
         // before the first token should match the whitespace of the arg
         // identifier.
@@ -220,6 +263,21 @@ void TokenLexer::ExpandFunctionArguments() {
 
       ResultToks.append(ArgToks, ArgToks+NumToks);
 
+      if(InstantiateLocStart.isValid()) {
+        SourceManager &SM = PP.getSourceManager();
+        SourceLocation curInst =
+            getMacroExpansionLocation(CurTok.getLocation());
+        assert(curInst.isValid() &&
+               "Expected arg identifier to come from definition");
+        for (unsigned i = ResultToks.size() - NumToks, e = ResultToks.size();
+               i != e; ++i) {
+          Token &Tok = ResultToks[i];
+          Tok.setLocation(SM.createInstantiationLoc(Tok.getLocation(),
+                                                    curInst, curInst,
+                                                    Tok.getLength()));
+        }
+      }
+
       // If this token (the macro argument) was supposed to get leading
       // whitespace, transfer this information onto the first token of the
       // expansion.
@@ -333,17 +391,29 @@ void TokenLexer::Lex(Token &Tok) {
     TokenIsFromPaste = true;
   }
 
+  SourceManager &SM = PP.getSourceManager();
   // The token's current location indicate where the token was lexed from.  We
   // need this information to compute the spelling of the token, but any
   // diagnostics for the expanded token should appear as if they came from
   // InstantiationLoc.  Pull this information together into a new SourceLocation
   // that captures all of this.
-  if (InstantiateLocStart.isValid()) {   // Don't do this for token streams.
-    SourceManager &SM = PP.getSourceManager();
-    Tok.setLocation(SM.createInstantiationLoc(Tok.getLocation(),
-                                              InstantiateLocStart,
-                                              InstantiateLocEnd,
-                                              Tok.getLength()));
+  if (InstantiateLocStart.isValid() &&   // Don't do this for token streams.
+      // Check that the token's location was not already set properly.
+      SM.isBeforeInSourceLocationOffset(Tok.getLocation(),
+                                        MacroStartSLocOffset)) {
+    SourceLocation instLoc;
+    if (Tok.is(tok::comment)) {
+      instLoc = SM.createInstantiationLoc(Tok.getLocation(),
+                                          InstantiateLocStart,
+                                          InstantiateLocEnd,
+                                          Tok.getLength());
+    } else {
+      instLoc = getMacroExpansionLocation(Tok.getLocation());
+      assert(instLoc.isValid() &&
+             "Location for token not coming from definition was not set!");
+    }
+
+    Tok.setLocation(instLoc);
   }
 
   // If this is the first token, set the lexical properties of the token to
@@ -381,9 +451,10 @@ void TokenLexer::Lex(Token &Tok) {
 bool TokenLexer::PasteTokens(Token &Tok) {
   llvm::SmallString<128> Buffer;
   const char *ResultTokStrPtr = 0;
+  SourceLocation PasteOpLoc;
   do {
     // Consume the ## operator.
-    SourceLocation PasteOpLoc = Tokens[CurToken].getLocation();
+    PasteOpLoc = Tokens[CurToken].getLocation();
     ++CurToken;
     assert(!isAtEnd() && "No token on the RHS of a paste operator!");
 
@@ -509,12 +580,30 @@ bool TokenLexer::PasteTokens(Token &Tok) {
     // Transfer properties of the LHS over the the Result.
     Result.setFlagValue(Token::StartOfLine , Tok.isAtStartOfLine());
     Result.setFlagValue(Token::LeadingSpace, Tok.hasLeadingSpace());
-
+    
     // Finally, replace LHS with the result, consume the RHS, and iterate.
     ++CurToken;
     Tok = Result;
   } while (!isAtEnd() && Tokens[CurToken].is(tok::hashhash));
 
+  // The token's current location indicate where the token was lexed from.  We
+  // need this information to compute the spelling of the token, but any
+  // diagnostics for the expanded token should appear as if the token was
+  // instantiated from the (##) operator. Pull this information together into
+  // a new SourceLocation that captures all of this.
+  if (InstantiateLocStart.isValid()) {
+    SourceManager &SM = PP.getSourceManager();
+    SourceLocation pasteLocInst =
+        getMacroExpansionLocation(PasteOpLoc);
+    assert(pasteLocInst.isValid() &&
+           "Expected '##' to come from definition");
+
+    Tok.setLocation(SM.createInstantiationLoc(Tok.getLocation(),
+                                              pasteLocInst,
+                                              pasteLocInst,
+                                              Tok.getLength()));
+  }
+
   // Now that we got the result token, it will be subject to expansion.  Since
   // token pasting re-lexes the result token in raw mode, identifier information
   // isn't looked up.  As such, if the result is an identifier, look up id info.
@@ -558,3 +647,23 @@ void TokenLexer::HandleMicrosoftCommentPaste(Token &Tok) {
 
   PP.HandleMicrosoftCommentPaste(Tok);
 }
+
+/// \brief If \arg loc is a FileID and points inside the current macro
+/// definition, returns the appropriate source location pointing at the
+/// macro expansion source location entry.
+SourceLocation TokenLexer::getMacroExpansionLocation(SourceLocation loc) const {
+  assert(InstantiateLocStart.isValid() && MacroExpansionStart.isValid() &&
+         "Not appropriate for token streams");
+  assert(loc.isValid());
+  
+  SourceManager &SM = PP.getSourceManager();
+  unsigned relativeOffset;
+  if (loc.isFileID() &&
+      SM.isInFileID(loc,
+                    MacroDefStartInfo.first, MacroDefStartInfo.second,
+                    Macro->getDefinitionLength(SM), &relativeOffset)) {
+    return MacroExpansionStart.getFileLocWithOffset(relativeOffset);
+  }
+
+  return SourceLocation();
+}
index 5e8bb53b2dee52b56927cdaf9024fabe987b48b6..f8652e0074758dd0c20cc640401f389e18f18c00 100644 (file)
@@ -310,7 +310,8 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
         SourceLocation FILoc = Tok.getLocation();
         const char *FIText = ": ";
         const SourceManager &SM = PP.getSourceManager();
-        if (FILoc.isFileID() || SM.isAtStartOfMacroInstantiation(FILoc)) {
+        if (FILoc.isFileID() ||
+            SM.isAtStartOfMacroInstantiation(FILoc, getLang())) {
           FILoc = SM.getInstantiationLoc(FILoc);
           bool IsInvalid = false;
           const char *SourcePtr =
index 58fd8ae84661699134906b757d553dddfdf50898..9f90b37d4162f71b9ed57993e51ffcd52d7bbf8a 100644 (file)
@@ -1,18 +1,40 @@
 // Test this without pch.
-// RUN: %clang_cc1 -include %S/variables.h -fsyntax-only -verify %s
+// RUN: %clang_cc1 -include %s -fsyntax-only -verify %s
 
 // Test with pch.
-// RUN: %clang_cc1 -emit-pch -o %t %S/variables.h
+// RUN: %clang_cc1 -emit-pch -o %t %s
 // RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s 
 
+#ifndef HEADER
+#define HEADER
+
+extern float y;
+extern int *ip, x;
+
+float z; // expected-note{{previous}}
+
+int z2 = 17; // expected-note{{previous}}
+
+#define MAKE_HAPPY(X) X##Happy
+int MAKE_HAPPY(Very); // expected-note{{previous definition is here}}
+
+#define A_MACRO_IN_THE_PCH 492
+#define FUNCLIKE_MACRO(X, Y) X ## Y
+
+#define PASTE2(x,y) x##y
+#define PASTE1(x,y) PASTE2(x,y)
+#define UNIQUE(x) PASTE1(x,__COUNTER__)
+
+int UNIQUE(a);  // a0
+int UNIQUE(a);  // a1
+
+#else
+
 int *ip2 = &x;
 float *fp = &ip; // expected-warning{{incompatible pointer types}}
-// FIXME:variables.h expected-note{{previous}}
 double z; // expected-error{{redefinition}}
-// FIXME:variables.h expected-note{{previous}}
 int z2 = 18; // expected-error{{redefinition}}
 double VeryHappy; // expected-error{{redefinition}}
-// FIXME:variables.h expected-note{{previous definition is here}}
 
 int Q = A_MACRO_IN_THE_PCH;
 
@@ -21,3 +43,5 @@ int R = FUNCLIKE_MACRO(A_MACRO_, IN_THE_PCH);
 
 int UNIQUE(a);  // a2
 int *Arr[] = { &a0, &a1, &a2 };
+
+#endif
index c9374297fc02613a3c6a54ea3adde9c9fa451fa2..23d2cd30cceba683c1238bf0065780df336c5092 100644 (file)
@@ -23,4 +23,3 @@ int MAKE_HAPPY(Very);
 
 int UNIQUE(a);  // a0
 int UNIQUE(a);  // a1
-
index 831687dcfcae3c22c257562e9ab0ca738ad6bbe1..0747aecd6c0492c6b96e7c31c0ec9c734d618411 100644 (file)
@@ -89,3 +89,12 @@ void test1(void) {
   int y = x;
   int z = y;
 }
+
+void test2(int x) {
+#define VALUE2 VALUE+VALUE
+#define VALUE3 VALUE+0
+#define VALUE4(x) x+0
+  x = VALUE2 // expected-error{{expected ';' after expression}}
+  x = VALUE3 // expected-error{{expected ';' after expression}}
+  x = VALUE4(0) // expected-error{{expected ';' after expression}}
+}