diff options
-rw-r--r-- | include/clang/Basic/SourceManager.h | 53 | ||||
-rw-r--r-- | include/clang/Lex/MacroInfo.h | 16 | ||||
-rw-r--r-- | include/clang/Lex/TokenLexer.h | 16 | ||||
-rw-r--r-- | lib/ARCMigrate/TransformActions.cpp | 4 | ||||
-rw-r--r-- | lib/ARCMigrate/Transforms.cpp | 2 | ||||
-rw-r--r-- | lib/Basic/SourceManager.cpp | 86 | ||||
-rw-r--r-- | lib/Lex/Lexer.cpp | 2 | ||||
-rw-r--r-- | lib/Lex/MacroArgs.cpp | 11 | ||||
-rw-r--r-- | lib/Lex/MacroArgs.h | 7 | ||||
-rw-r--r-- | lib/Lex/MacroInfo.cpp | 32 | ||||
-rw-r--r-- | lib/Lex/TokenLexer.cpp | 129 | ||||
-rw-r--r-- | lib/Parse/ParseExpr.cpp | 3 | ||||
-rw-r--r-- | test/PCH/variables.c | 34 | ||||
-rw-r--r-- | test/PCH/variables.h | 1 | ||||
-rw-r--r-- | test/Parser/recovery.c | 9 |
15 files changed, 324 insertions, 81 deletions
diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h index 05551e5319..33c66e7f7c 100644 --- a/include/clang/Basic/SourceManager.h +++ b/include/clang/Basic/SourceManager.h @@ -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; diff --git a/include/clang/Lex/MacroInfo.h b/include/clang/Lex/MacroInfo.h index 7c4cfb0072..9e9d7cf500 100644 --- a/include/clang/Lex/MacroInfo.h +++ b/include/clang/Lex/MacroInfo.h @@ -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 diff --git a/include/clang/Lex/TokenLexer.h b/include/clang/Lex/TokenLexer.h index 8f530053ca..ea36e0e0e8 100644 --- a/include/clang/Lex/TokenLexer.h +++ b/include/clang/Lex/TokenLexer.h @@ -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 diff --git a/lib/ARCMigrate/TransformActions.cpp b/lib/ARCMigrate/TransformActions.cpp index cd8a80e86b..45a3d473e6 100644 --- a/lib/ARCMigrate/TransformActions.cpp +++ b/lib/ARCMigrate/TransformActions.cpp @@ -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) { diff --git a/lib/ARCMigrate/Transforms.cpp b/lib/ARCMigrate/Transforms.cpp index 80445c70ac..1a98833fe0 100644 --- a/lib/ARCMigrate/Transforms.cpp +++ b/lib/ARCMigrate/Transforms.cpp @@ -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; } diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp index d6c4c16cec..137da0d87a 100644 --- a/lib/Basic/SourceManager.cpp +++ b/lib/Basic/SourceManager.cpp @@ -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); diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp index 608bd9d0c5..6d25d2b2cf 100644 --- a/lib/Lex/Lexer.cpp +++ b/lib/Lex/Lexer.cpp @@ -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. diff --git a/lib/Lex/MacroArgs.cpp b/lib/Lex/MacroArgs.cpp index dee7da38aa..968c15e3c2 100644 --- a/lib/Lex/MacroArgs.cpp +++ b/lib/Lex/MacroArgs.cpp @@ -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]; } diff --git a/lib/Lex/MacroArgs.h b/lib/Lex/MacroArgs.h index 6ff4856b4e..a962dacf7c 100644 --- a/lib/Lex/MacroArgs.h +++ b/lib/Lex/MacroArgs.h @@ -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 diff --git a/lib/Lex/MacroInfo.cpp b/lib/Lex/MacroInfo.cpp index 66d87a1938..0a16a25672 100644 --- a/lib/Lex/MacroInfo.cpp +++ b/lib/Lex/MacroInfo.cpp @@ -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. diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp index f30c44e0e6..db37fe15f3 100644 --- a/lib/Lex/TokenLexer.cpp +++ b/lib/Lex/TokenLexer.cpp @@ -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(); +} diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 5e8bb53b2d..f8652e0074 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -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 = diff --git a/test/PCH/variables.c b/test/PCH/variables.c index 58fd8ae846..9f90b37d41 100644 --- a/test/PCH/variables.c +++ b/test/PCH/variables.c @@ -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 diff --git a/test/PCH/variables.h b/test/PCH/variables.h index c9374297fc..23d2cd30cc 100644 --- a/test/PCH/variables.h +++ b/test/PCH/variables.h @@ -23,4 +23,3 @@ int MAKE_HAPPY(Very); int UNIQUE(a); // a0 int UNIQUE(a); // a1 - diff --git a/test/Parser/recovery.c b/test/Parser/recovery.c index 831687dcfc..0747aecd6c 100644 --- a/test/Parser/recovery.c +++ b/test/Parser/recovery.c @@ -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}} +} |