class FileManager;
class FileEntry;
class LineTableInfo;
+class LangOptions;
/// SrcMgr - Public enums and private classes that are part of the
/// SourceManager implementation.
/// \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
/// \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;
/// 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;
/// 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
/// 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);
}
assert(!IsDisabled && "Cannot disable an already-disabled macro!");
IsDisabled = true;
}
+
+private:
+ unsigned getDefinitionLengthSlow(SourceManager &SM) const;
};
} // end namespace clang
/// 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;
/// 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
if (loc.isFileID())
return true;
- return SM.isAtStartOfMacroInstantiation(loc);
+ return SM.isAtStartOfMacroInstantiation(loc, Ctx.getLangOptions());
}
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) {
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;
}
//
//===----------------------------------------------------------------------===//
+#include "clang/Lex/Lexer.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/SourceManagerInternals.h"
#include "clang/Basic/Diagnostic.h"
/// \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);
}
//===----------------------------------------------------------------------===//
// 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);
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.
/// 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);
}
}
- 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());
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];
}
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.
/// 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.
/// 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
IsUsed = false;
IsAllowRedefinitionsWithoutWarning = false;
IsWarnIfUnused = false;
+ IsDefinitionLengthCached = false;
ArgumentList = 0;
NumArguments = 0;
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.
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.
InstantiateLocStart = InstantiateLocEnd = SourceLocation();
AtStartOfLine = false;
HasLeadingSpace = false;
+ MacroExpansionStart = SourceLocation();
// Set HasLeadingSpace/AtStartOfLine so that the first token will be
// returned unmodified.
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
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.
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.
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
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!");
// 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.
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();
+}
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 =
// 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;
int UNIQUE(a); // a2
int *Arr[] = { &a0, &a1, &a2 };
+
+#endif
int UNIQUE(a); // a0
int UNIQUE(a); // a1
-
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}}
+}