[cfe-commits] r134587 - in /cfe/trunk: 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

Argyrios Kyrtzidis akyrtzi at gmail.com
Wed Jul 6 20:40:34 PDT 2011


Author: akirtzidis
Date: Wed Jul  6 22:40:34 2011
New Revision: 134587

URL: http://llvm.org/viewvc/llvm-project?rev=134587&view=rev
Log:
Make the Preprocessor more memory efficient and improve macro instantiation diagnostics.

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)

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

Modified: cfe/trunk/include/clang/Basic/SourceManager.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/SourceManager.h?rev=134587&r1=134586&r2=134587&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/SourceManager.h (original)
+++ cfe/trunk/include/clang/Basic/SourceManager.h Wed Jul  6 22:40:34 2011
@@ -36,6 +36,7 @@
 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 @@
 
   /// \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 @@
   /// \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;

Modified: cfe/trunk/include/clang/Lex/MacroInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/MacroInfo.h?rev=134587&r1=134586&r2=134587&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/MacroInfo.h (original)
+++ cfe/trunk/include/clang/Lex/MacroInfo.h Wed Jul  6 22:40:34 2011
@@ -43,6 +43,10 @@
   /// 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 @@
   /// 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 @@
   /// 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 @@
     assert(!IsDisabled && "Cannot disable an already-disabled macro!");
     IsDisabled = true;
   }
+
+private:
+  unsigned getDefinitionLengthSlow(SourceManager &SM) const;
 };
 
 }  // end namespace clang

Modified: cfe/trunk/include/clang/Lex/TokenLexer.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/TokenLexer.h?rev=134587&r1=134586&r2=134587&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/TokenLexer.h (original)
+++ cfe/trunk/include/clang/Lex/TokenLexer.h Wed Jul  6 22:40:34 2011
@@ -63,6 +63,17 @@
   /// 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 @@
   /// 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

Modified: cfe/trunk/lib/ARCMigrate/TransformActions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ARCMigrate/TransformActions.cpp?rev=134587&r1=134586&r2=134587&view=diff
==============================================================================
--- cfe/trunk/lib/ARCMigrate/TransformActions.cpp (original)
+++ cfe/trunk/lib/ARCMigrate/TransformActions.cpp Wed Jul  6 22:40:34 2011
@@ -388,7 +388,7 @@
 
   if (loc.isFileID())
     return true;
-  return SM.isAtStartOfMacroInstantiation(loc);
+  return SM.isAtStartOfMacroInstantiation(loc, Ctx.getLangOptions());
 }
 
 bool TransformActionsImpl::canInsertAfterToken(SourceLocation loc) {
@@ -401,7 +401,7 @@
 
   if (loc.isFileID())
     return true;
-  return SM.isAtEndOfMacroInstantiation(loc);
+  return SM.isAtEndOfMacroInstantiation(loc, Ctx.getLangOptions());
 }
 
 bool TransformActionsImpl::canRemoveRange(SourceRange range) {

Modified: cfe/trunk/lib/ARCMigrate/Transforms.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ARCMigrate/Transforms.cpp?rev=134587&r1=134586&r2=134587&view=diff
==============================================================================
--- cfe/trunk/lib/ARCMigrate/Transforms.cpp (original)
+++ cfe/trunk/lib/ARCMigrate/Transforms.cpp Wed Jul  6 22:40:34 2011
@@ -37,7 +37,7 @@
                                             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;
   }

Modified: cfe/trunk/lib/Basic/SourceManager.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/SourceManager.cpp?rev=134587&r1=134586&r2=134587&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/SourceManager.cpp (original)
+++ cfe/trunk/lib/Basic/SourceManager.cpp Wed Jul  6 22:40:34 2011
@@ -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 @@
 
 /// \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;
-
-  // 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;
+  SourceLocation instLoc = 
+      getSLocEntry(infoLoc.first).getInstantiation().getInstantiationLocStart();
+  if (instLoc.isFileID())
+    return true; // No other macro instantiations, this is the first.
 
-  // 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;
 
-  // If there's no FileID after it, it is the last token in the macro.
-  if (FID+1 == sloc_entry_size())
-    return true;
+  std::pair<FileID, unsigned> infoLoc = getDecomposedLoc(loc);
+  unsigned FID = infoLoc.first.ID;
 
-  bool invalid = false;
-  const SrcMgr::SLocEntry &Entry = getSLocEntry(FID+1, &invalid);
-  if (invalid)
-    return false;
+  unsigned NextOffset;
+  if (FID+1 == sloc_entry_size())
+    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 @@
   // 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);

Modified: cfe/trunk/lib/Lex/Lexer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/Lexer.cpp?rev=134587&r1=134586&r2=134587&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/Lexer.cpp (original)
+++ cfe/trunk/lib/Lex/Lexer.cpp Wed Jul  6 22:40:34 2011
@@ -683,7 +683,7 @@
     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.

Modified: cfe/trunk/lib/Lex/MacroArgs.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/MacroArgs.cpp?rev=134587&r1=134586&r2=134587&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/MacroArgs.cpp (original)
+++ cfe/trunk/lib/Lex/MacroArgs.cpp Wed Jul  6 22:40:34 2011
@@ -185,7 +185,8 @@
 /// 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 @@
     }
   }
 
-  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 @@
            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];
 }

Modified: cfe/trunk/lib/Lex/MacroArgs.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/MacroArgs.h?rev=134587&r1=134586&r2=134587&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/MacroArgs.h (original)
+++ cfe/trunk/lib/Lex/MacroArgs.h Wed Jul  6 22:40:34 2011
@@ -20,6 +20,7 @@
   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 @@
 
   /// 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 @@
   /// 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

Modified: cfe/trunk/lib/Lex/MacroInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/MacroInfo.cpp?rev=134587&r1=134586&r2=134587&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/MacroInfo.cpp (original)
+++ cfe/trunk/lib/Lex/MacroInfo.cpp Wed Jul  6 22:40:34 2011
@@ -25,6 +25,7 @@
   IsUsed = false;
   IsAllowRedefinitionsWithoutWarning = false;
   IsWarnIfUnused = false;
+  IsDefinitionLengthCached = false;
 
   ArgumentList = 0;
   NumArguments = 0;
@@ -43,11 +44,42 @@
   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.

Modified: cfe/trunk/lib/Lex/TokenLexer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/TokenLexer.cpp?rev=134587&r1=134586&r2=134587&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/TokenLexer.cpp (original)
+++ cfe/trunk/lib/Lex/TokenLexer.cpp Wed Jul  6 22:40:34 2011
@@ -40,6 +40,28 @@
   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 @@
   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 @@
       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 @@
         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 @@
 
       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 @@
     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 @@
 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 @@
     // 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 @@
 
   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();
+}

Modified: cfe/trunk/lib/Parse/ParseExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=134587&r1=134586&r2=134587&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Wed Jul  6 22:40:34 2011
@@ -310,7 +310,8 @@
         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 =

Modified: cfe/trunk/test/PCH/variables.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/variables.c?rev=134587&r1=134586&r2=134587&view=diff
==============================================================================
--- cfe/trunk/test/PCH/variables.c (original)
+++ cfe/trunk/test/PCH/variables.c Wed Jul  6 22:40:34 2011
@@ -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 UNIQUE(a);  // a2
 int *Arr[] = { &a0, &a1, &a2 };
+
+#endif

Modified: cfe/trunk/test/PCH/variables.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/variables.h?rev=134587&r1=134586&r2=134587&view=diff
==============================================================================
--- cfe/trunk/test/PCH/variables.h (original)
+++ cfe/trunk/test/PCH/variables.h Wed Jul  6 22:40:34 2011
@@ -23,4 +23,3 @@
 
 int UNIQUE(a);  // a0
 int UNIQUE(a);  // a1
-

Modified: cfe/trunk/test/Parser/recovery.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/recovery.c?rev=134587&r1=134586&r2=134587&view=diff
==============================================================================
--- cfe/trunk/test/Parser/recovery.c (original)
+++ cfe/trunk/test/Parser/recovery.c Wed Jul  6 22:40:34 2011
@@ -89,3 +89,12 @@
   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}}
+}





More information about the cfe-commits mailing list