]> granicus.if.org Git - clang/commitdiff
When expanding macro arguments, treat '##' coming from an argument as a normal token.
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>
Thu, 7 Jul 2011 03:40:37 +0000 (03:40 +0000)
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>
Thu, 7 Jul 2011 03:40:37 +0000 (03:40 +0000)
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

lib/Lex/TokenLexer.cpp
test/Preprocessor/macro_paste_hashhash.c

index db37fe15f384c0f599b0e219f37f58d8c4c80a2c..586f26fd2bcce6c12c873f5540de53c93f422b37 100644 (file)
@@ -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<Token, 128> 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
index e7993cc0a3517ad9b54e2b0bbd25ca2da962f0d4..f4b03bef2e16703d32cbacfdc482ecb490d1a3cf 100644 (file)
@@ -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(##);