From: Argyrios Kyrtzidis Date: Thu, 7 Jul 2011 03:40:37 +0000 (+0000) Subject: When expanding macro arguments, treat '##' coming from an argument as a normal token. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0fd9c48dfc6a324d8399b0b43ab4b943a1b1b843;p=clang When expanding macro arguments, treat '##' coming from an argument as a normal token. e.g. #define M(x) A x B M(##) // should expand to 'A ## B', not 'AB' git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@134588 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp index db37fe15f3..586f26fd2b 100644 --- a/lib/Lex/TokenLexer.cpp +++ b/lib/Lex/TokenLexer.cpp @@ -121,6 +121,8 @@ void TokenLexer::destroy() { /// Expand the arguments of a function-like macro so that we can quickly /// return preexpanded tokens from Tokens. void TokenLexer::ExpandFunctionArguments() { + SourceManager &SM = PP.getSourceManager(); + llvm::SmallVector ResultToks; // Loop through 'Tokens', expanding them into ResultToks. Keep @@ -191,7 +193,10 @@ void TokenLexer::ExpandFunctionArguments() { // Otherwise, this is a use of the argument. Find out if there is a paste // (##) operator before or after the argument. bool PasteBefore = - !ResultToks.empty() && ResultToks.back().is(tok::hashhash); + !ResultToks.empty() && ResultToks.back().is(tok::hashhash) && + // If the '##' came from expanding an argument,treat it as a normal token. + SM.isBeforeInSourceLocationOffset(ResultToks.back().getLocation(), + MacroStartSLocOffset); bool PasteAfter = i+1 != e && Tokens[i+1].is(tok::hashhash); // If it is not the LHS/RHS of a ## operator, we must pre-expand the @@ -215,7 +220,6 @@ void TokenLexer::ExpandFunctionArguments() { ResultToks.append(ResultArgToks, ResultArgToks+NumToks); if(InstantiateLocStart.isValid()) { - SourceManager &SM = PP.getSourceManager(); SourceLocation curInst = getMacroExpansionLocation(CurTok.getLocation()); assert(curInst.isValid() && @@ -264,7 +268,6 @@ void TokenLexer::ExpandFunctionArguments() { ResultToks.append(ArgToks, ArgToks+NumToks); if(InstantiateLocStart.isValid()) { - SourceManager &SM = PP.getSourceManager(); SourceLocation curInst = getMacroExpansionLocation(CurTok.getLocation()); assert(curInst.isValid() && @@ -371,6 +374,8 @@ void TokenLexer::Lex(Token &Tok) { return PPCache.Lex(Tok); } + SourceManager &SM = PP.getSourceManager(); + // If this is the first token of the expanded result, we inherit spacing // properties later. bool isFirstToken = CurToken == 0; @@ -382,7 +387,10 @@ void TokenLexer::Lex(Token &Tok) { // If this token is followed by a token paste (##) operator, paste the tokens! // Note that ## is a normal token when not expanding a macro. - if (!isAtEnd() && Tokens[CurToken].is(tok::hashhash) && Macro) { + if (!isAtEnd() && Tokens[CurToken].is(tok::hashhash) && Macro && + // If the '##' came from expanding an argument,treat it as a normal token. + SM.isBeforeInSourceLocationOffset(Tokens[CurToken].getLocation(), + MacroStartSLocOffset)) { // When handling the microsoft /##/ extension, the final token is // returned by PasteTokens, not the pasted token. if (PasteTokens(Tok)) @@ -391,7 +399,6 @@ 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 diff --git a/test/Preprocessor/macro_paste_hashhash.c b/test/Preprocessor/macro_paste_hashhash.c index e7993cc0a3..f4b03bef2e 100644 --- a/test/Preprocessor/macro_paste_hashhash.c +++ b/test/Preprocessor/macro_paste_hashhash.c @@ -1,7 +1,11 @@ -// RUN: %clang_cc1 -E %s | grep '^"x ## y";$' +// RUN: %clang_cc1 -E %s | FileCheck %s #define hash_hash # ## # #define mkstr(a) # a #define in_between(a) mkstr(a) #define join(c, d) in_between(c hash_hash d) +// CHECK: "x ## y"; join(x, y); +#define FOO(x) A x B +// CHECK: A ## B; +FOO(##);