Chris Lattner | d7038e1 | 2009-02-13 00:46:04 +0000 | [diff] [blame] | 1 | //===--- TokenConcatenation.cpp - Token Concatenation Avoidance -----------===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This file implements the TokenConcatenation class. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | #include "clang/Lex/TokenConcatenation.h" |
| 15 | #include "clang/Lex/Preprocessor.h" |
Abramo Bagnara | c4bf2b9 | 2010-12-22 08:23:18 +0000 | [diff] [blame] | 16 | #include "llvm/Support/ErrorHandling.h" |
Joerg Sonnenberger | 7094dee | 2012-08-10 10:58:18 +0000 | [diff] [blame] | 17 | #include <cctype> |
Mike Stump | 1eb4433 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 18 | using namespace clang; |
Chris Lattner | d7038e1 | 2009-02-13 00:46:04 +0000 | [diff] [blame] | 19 | |
| 20 | |
Craig Topper | 2fa4e86 | 2011-08-11 04:06:15 +0000 | [diff] [blame] | 21 | /// IsStringPrefix - Return true if Str is a string prefix. |
| 22 | /// 'L', 'u', 'U', or 'u8'. Including raw versions. |
Craig Topper | 03720fc | 2011-08-11 05:10:55 +0000 | [diff] [blame] | 23 | static bool IsStringPrefix(StringRef Str, bool CPlusPlus0x) { |
Craig Topper | 2fa4e86 | 2011-08-11 04:06:15 +0000 | [diff] [blame] | 24 | |
| 25 | if (Str[0] == 'L' || |
| 26 | (CPlusPlus0x && (Str[0] == 'u' || Str[0] == 'U' || Str[0] == 'R'))) { |
| 27 | |
| 28 | if (Str.size() == 1) |
| 29 | return true; // "L", "u", "U", and "R" |
| 30 | |
| 31 | // Check for raw flavors. Need to make sure the first character wasn't |
| 32 | // already R. Need CPlusPlus0x check for "LR". |
| 33 | if (Str[1] == 'R' && Str[0] != 'R' && Str.size() == 2 && CPlusPlus0x) |
| 34 | return true; // "LR", "uR", "UR" |
| 35 | |
| 36 | // Check for "u8" and "u8R" |
| 37 | if (Str[0] == 'u' && Str[1] == '8') { |
| 38 | if (Str.size() == 2) return true; // "u8" |
| 39 | if (Str.size() == 3 && Str[2] == 'R') return true; // "u8R" |
| 40 | } |
| 41 | } |
| 42 | |
| 43 | return false; |
| 44 | } |
| 45 | |
Douglas Gregor | 5cee119 | 2011-07-27 05:40:30 +0000 | [diff] [blame] | 46 | /// IsIdentifierStringPrefix - Return true if the spelling of the token |
Craig Topper | 2fa4e86 | 2011-08-11 04:06:15 +0000 | [diff] [blame] | 47 | /// is literally 'L', 'u', 'U', or 'u8'. Including raw versions. |
Douglas Gregor | 5cee119 | 2011-07-27 05:40:30 +0000 | [diff] [blame] | 48 | bool TokenConcatenation::IsIdentifierStringPrefix(const Token &Tok) const { |
David Blaikie | 4e4d084 | 2012-03-11 07:00:24 +0000 | [diff] [blame] | 49 | const LangOptions &LangOpts = PP.getLangOpts(); |
Douglas Gregor | 5cee119 | 2011-07-27 05:40:30 +0000 | [diff] [blame] | 50 | |
Chris Lattner | d7038e1 | 2009-02-13 00:46:04 +0000 | [diff] [blame] | 51 | if (!Tok.needsCleaning()) { |
Craig Topper | 2fa4e86 | 2011-08-11 04:06:15 +0000 | [diff] [blame] | 52 | if (Tok.getLength() < 1 || Tok.getLength() > 3) |
Douglas Gregor | 5cee119 | 2011-07-27 05:40:30 +0000 | [diff] [blame] | 53 | return false; |
Chris Lattner | d7038e1 | 2009-02-13 00:46:04 +0000 | [diff] [blame] | 54 | SourceManager &SM = PP.getSourceManager(); |
Douglas Gregor | 5cee119 | 2011-07-27 05:40:30 +0000 | [diff] [blame] | 55 | const char *Ptr = SM.getCharacterData(SM.getSpellingLoc(Tok.getLocation())); |
Craig Topper | 2fa4e86 | 2011-08-11 04:06:15 +0000 | [diff] [blame] | 56 | return IsStringPrefix(StringRef(Ptr, Tok.getLength()), |
| 57 | LangOpts.CPlusPlus0x); |
Chris Lattner | d7038e1 | 2009-02-13 00:46:04 +0000 | [diff] [blame] | 58 | } |
Mike Stump | 1eb4433 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 59 | |
Chris Lattner | d7038e1 | 2009-02-13 00:46:04 +0000 | [diff] [blame] | 60 | if (Tok.getLength() < 256) { |
| 61 | char Buffer[256]; |
| 62 | const char *TokPtr = Buffer; |
Douglas Gregor | 5cee119 | 2011-07-27 05:40:30 +0000 | [diff] [blame] | 63 | unsigned length = PP.getSpelling(Tok, TokPtr); |
Craig Topper | 2fa4e86 | 2011-08-11 04:06:15 +0000 | [diff] [blame] | 64 | return IsStringPrefix(StringRef(TokPtr, length), LangOpts.CPlusPlus0x); |
Chris Lattner | d7038e1 | 2009-02-13 00:46:04 +0000 | [diff] [blame] | 65 | } |
Mike Stump | 1eb4433 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 66 | |
Craig Topper | 2fa4e86 | 2011-08-11 04:06:15 +0000 | [diff] [blame] | 67 | return IsStringPrefix(StringRef(PP.getSpelling(Tok)), LangOpts.CPlusPlus0x); |
Chris Lattner | d7038e1 | 2009-02-13 00:46:04 +0000 | [diff] [blame] | 68 | } |
| 69 | |
| 70 | TokenConcatenation::TokenConcatenation(Preprocessor &pp) : PP(pp) { |
| 71 | memset(TokenInfo, 0, sizeof(TokenInfo)); |
Mike Stump | 1eb4433 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 72 | |
Chris Lattner | d7038e1 | 2009-02-13 00:46:04 +0000 | [diff] [blame] | 73 | // These tokens have custom code in AvoidConcat. |
| 74 | TokenInfo[tok::identifier ] |= aci_custom; |
| 75 | TokenInfo[tok::numeric_constant] |= aci_custom_firstchar; |
| 76 | TokenInfo[tok::period ] |= aci_custom_firstchar; |
| 77 | TokenInfo[tok::amp ] |= aci_custom_firstchar; |
| 78 | TokenInfo[tok::plus ] |= aci_custom_firstchar; |
| 79 | TokenInfo[tok::minus ] |= aci_custom_firstchar; |
| 80 | TokenInfo[tok::slash ] |= aci_custom_firstchar; |
| 81 | TokenInfo[tok::less ] |= aci_custom_firstchar; |
| 82 | TokenInfo[tok::greater ] |= aci_custom_firstchar; |
| 83 | TokenInfo[tok::pipe ] |= aci_custom_firstchar; |
| 84 | TokenInfo[tok::percent ] |= aci_custom_firstchar; |
| 85 | TokenInfo[tok::colon ] |= aci_custom_firstchar; |
| 86 | TokenInfo[tok::hash ] |= aci_custom_firstchar; |
| 87 | TokenInfo[tok::arrow ] |= aci_custom_firstchar; |
Mike Stump | 1eb4433 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 88 | |
Richard Smith | 99831e4 | 2012-03-06 03:21:47 +0000 | [diff] [blame] | 89 | // These tokens have custom code in C++11 mode. |
David Blaikie | 4e4d084 | 2012-03-11 07:00:24 +0000 | [diff] [blame] | 90 | if (PP.getLangOpts().CPlusPlus0x) { |
Richard Smith | 99831e4 | 2012-03-06 03:21:47 +0000 | [diff] [blame] | 91 | TokenInfo[tok::string_literal ] |= aci_custom; |
| 92 | TokenInfo[tok::wide_string_literal ] |= aci_custom; |
| 93 | TokenInfo[tok::utf8_string_literal ] |= aci_custom; |
| 94 | TokenInfo[tok::utf16_string_literal] |= aci_custom; |
| 95 | TokenInfo[tok::utf32_string_literal] |= aci_custom; |
| 96 | TokenInfo[tok::char_constant ] |= aci_custom; |
| 97 | TokenInfo[tok::wide_char_constant ] |= aci_custom; |
| 98 | TokenInfo[tok::utf16_char_constant ] |= aci_custom; |
| 99 | TokenInfo[tok::utf32_char_constant ] |= aci_custom; |
| 100 | } |
| 101 | |
Chris Lattner | d7038e1 | 2009-02-13 00:46:04 +0000 | [diff] [blame] | 102 | // These tokens change behavior if followed by an '='. |
| 103 | TokenInfo[tok::amp ] |= aci_avoid_equal; // &= |
| 104 | TokenInfo[tok::plus ] |= aci_avoid_equal; // += |
| 105 | TokenInfo[tok::minus ] |= aci_avoid_equal; // -= |
| 106 | TokenInfo[tok::slash ] |= aci_avoid_equal; // /= |
| 107 | TokenInfo[tok::less ] |= aci_avoid_equal; // <= |
| 108 | TokenInfo[tok::greater ] |= aci_avoid_equal; // >= |
| 109 | TokenInfo[tok::pipe ] |= aci_avoid_equal; // |= |
| 110 | TokenInfo[tok::percent ] |= aci_avoid_equal; // %= |
| 111 | TokenInfo[tok::star ] |= aci_avoid_equal; // *= |
| 112 | TokenInfo[tok::exclaim ] |= aci_avoid_equal; // != |
| 113 | TokenInfo[tok::lessless ] |= aci_avoid_equal; // <<= |
Chris Lattner | 8685110 | 2010-03-26 17:10:02 +0000 | [diff] [blame] | 114 | TokenInfo[tok::greatergreater] |= aci_avoid_equal; // >>= |
Chris Lattner | d7038e1 | 2009-02-13 00:46:04 +0000 | [diff] [blame] | 115 | TokenInfo[tok::caret ] |= aci_avoid_equal; // ^= |
| 116 | TokenInfo[tok::equal ] |= aci_avoid_equal; // == |
| 117 | } |
| 118 | |
Daniel Dunbar | 99c7622 | 2009-03-18 03:32:24 +0000 | [diff] [blame] | 119 | /// GetFirstChar - Get the first character of the token \arg Tok, |
| 120 | /// avoiding calls to getSpelling where possible. |
| 121 | static char GetFirstChar(Preprocessor &PP, const Token &Tok) { |
| 122 | if (IdentifierInfo *II = Tok.getIdentifierInfo()) { |
| 123 | // Avoid spelling identifiers, the most common form of token. |
Daniel Dunbar | e013d68 | 2009-10-18 20:26:12 +0000 | [diff] [blame] | 124 | return II->getNameStart()[0]; |
Daniel Dunbar | 99c7622 | 2009-03-18 03:32:24 +0000 | [diff] [blame] | 125 | } else if (!Tok.needsCleaning()) { |
| 126 | if (Tok.isLiteral() && Tok.getLiteralData()) { |
| 127 | return *Tok.getLiteralData(); |
| 128 | } else { |
| 129 | SourceManager &SM = PP.getSourceManager(); |
| 130 | return *SM.getCharacterData(SM.getSpellingLoc(Tok.getLocation())); |
| 131 | } |
| 132 | } else if (Tok.getLength() < 256) { |
| 133 | char Buffer[256]; |
| 134 | const char *TokPtr = Buffer; |
| 135 | PP.getSpelling(Tok, TokPtr); |
| 136 | return TokPtr[0]; |
| 137 | } else { |
| 138 | return PP.getSpelling(Tok)[0]; |
| 139 | } |
| 140 | } |
| 141 | |
Chris Lattner | d7038e1 | 2009-02-13 00:46:04 +0000 | [diff] [blame] | 142 | /// AvoidConcat - If printing PrevTok immediately followed by Tok would cause |
| 143 | /// the two individual tokens to be lexed as a single token, return true |
| 144 | /// (which causes a space to be printed between them). This allows the output |
| 145 | /// of -E mode to be lexed to the same token stream as lexing the input |
| 146 | /// directly would. |
| 147 | /// |
| 148 | /// This code must conservatively return true if it doesn't want to be 100% |
| 149 | /// accurate. This will cause the output to include extra space characters, |
| 150 | /// but the resulting output won't have incorrect concatenations going on. |
| 151 | /// Examples include "..", which we print with a space between, because we |
| 152 | /// don't want to track enough to tell "x.." from "...". |
Chris Lattner | 8877321 | 2010-04-14 03:57:19 +0000 | [diff] [blame] | 153 | bool TokenConcatenation::AvoidConcat(const Token &PrevPrevTok, |
| 154 | const Token &PrevTok, |
Chris Lattner | d7038e1 | 2009-02-13 00:46:04 +0000 | [diff] [blame] | 155 | const Token &Tok) const { |
Chris Lattner | e1614bb | 2009-04-21 23:28:41 +0000 | [diff] [blame] | 156 | // First, check to see if the tokens were directly adjacent in the original |
| 157 | // source. If they were, it must be okay to stick them together: if there |
| 158 | // were an issue, the tokens would have been lexed differently. |
| 159 | if (PrevTok.getLocation().isFileID() && Tok.getLocation().isFileID() && |
Argyrios Kyrtzidis | a64ccef | 2011-09-19 20:40:19 +0000 | [diff] [blame] | 160 | PrevTok.getLocation().getLocWithOffset(PrevTok.getLength()) == |
Chris Lattner | e1614bb | 2009-04-21 23:28:41 +0000 | [diff] [blame] | 161 | Tok.getLocation()) |
| 162 | return false; |
Mike Stump | 1eb4433 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 163 | |
Chris Lattner | d7038e1 | 2009-02-13 00:46:04 +0000 | [diff] [blame] | 164 | tok::TokenKind PrevKind = PrevTok.getKind(); |
| 165 | if (PrevTok.getIdentifierInfo()) // Language keyword or named operator. |
| 166 | PrevKind = tok::identifier; |
Mike Stump | 1eb4433 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 167 | |
Chris Lattner | d7038e1 | 2009-02-13 00:46:04 +0000 | [diff] [blame] | 168 | // Look up information on when we should avoid concatenation with prevtok. |
| 169 | unsigned ConcatInfo = TokenInfo[PrevKind]; |
Mike Stump | 1eb4433 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 170 | |
Chris Lattner | d7038e1 | 2009-02-13 00:46:04 +0000 | [diff] [blame] | 171 | // If prevtok never causes a problem for anything after it, return quickly. |
| 172 | if (ConcatInfo == 0) return false; |
Mike Stump | 1eb4433 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 173 | |
Chris Lattner | d7038e1 | 2009-02-13 00:46:04 +0000 | [diff] [blame] | 174 | if (ConcatInfo & aci_avoid_equal) { |
| 175 | // If the next token is '=' or '==', avoid concatenation. |
| 176 | if (Tok.is(tok::equal) || Tok.is(tok::equalequal)) |
| 177 | return true; |
| 178 | ConcatInfo &= ~aci_avoid_equal; |
| 179 | } |
Mike Stump | 1eb4433 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 180 | |
Chris Lattner | d7038e1 | 2009-02-13 00:46:04 +0000 | [diff] [blame] | 181 | if (ConcatInfo == 0) return false; |
Mike Stump | 1eb4433 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 182 | |
Chris Lattner | d7038e1 | 2009-02-13 00:46:04 +0000 | [diff] [blame] | 183 | // Basic algorithm: we look at the first character of the second token, and |
| 184 | // determine whether it, if appended to the first token, would form (or |
| 185 | // would contribute) to a larger token if concatenated. |
| 186 | char FirstChar = 0; |
| 187 | if (ConcatInfo & aci_custom) { |
| 188 | // If the token does not need to know the first character, don't get it. |
Chris Lattner | d7038e1 | 2009-02-13 00:46:04 +0000 | [diff] [blame] | 189 | } else { |
Daniel Dunbar | 99c7622 | 2009-03-18 03:32:24 +0000 | [diff] [blame] | 190 | FirstChar = GetFirstChar(PP, Tok); |
Chris Lattner | d7038e1 | 2009-02-13 00:46:04 +0000 | [diff] [blame] | 191 | } |
Mike Stump | 1eb4433 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 192 | |
Chris Lattner | d7038e1 | 2009-02-13 00:46:04 +0000 | [diff] [blame] | 193 | switch (PrevKind) { |
Abramo Bagnara | c4bf2b9 | 2010-12-22 08:23:18 +0000 | [diff] [blame] | 194 | default: |
| 195 | llvm_unreachable("InitAvoidConcatTokenInfo built wrong"); |
Abramo Bagnara | c4bf2b9 | 2010-12-22 08:23:18 +0000 | [diff] [blame] | 196 | |
| 197 | case tok::raw_identifier: |
| 198 | llvm_unreachable("tok::raw_identifier in non-raw lexing mode!"); |
Abramo Bagnara | c4bf2b9 | 2010-12-22 08:23:18 +0000 | [diff] [blame] | 199 | |
Richard Smith | 99831e4 | 2012-03-06 03:21:47 +0000 | [diff] [blame] | 200 | case tok::string_literal: |
| 201 | case tok::wide_string_literal: |
| 202 | case tok::utf8_string_literal: |
| 203 | case tok::utf16_string_literal: |
| 204 | case tok::utf32_string_literal: |
| 205 | case tok::char_constant: |
| 206 | case tok::wide_char_constant: |
| 207 | case tok::utf16_char_constant: |
| 208 | case tok::utf32_char_constant: |
David Blaikie | 4e4d084 | 2012-03-11 07:00:24 +0000 | [diff] [blame] | 209 | if (!PP.getLangOpts().CPlusPlus0x) |
Richard Smith | 99831e4 | 2012-03-06 03:21:47 +0000 | [diff] [blame] | 210 | return false; |
| 211 | |
| 212 | // In C++11, a string or character literal followed by an identifier is a |
| 213 | // single token. |
| 214 | if (Tok.getIdentifierInfo()) |
| 215 | return true; |
| 216 | |
| 217 | // A ud-suffix is an identifier. If the previous token ends with one, treat |
| 218 | // it as an identifier. |
| 219 | if (!PrevTok.hasUDSuffix()) |
| 220 | return false; |
| 221 | // FALL THROUGH. |
Mike Stump | 1eb4433 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 222 | case tok::identifier: // id+id or id+number or id+L"foo". |
Daniel Dunbar | 99c7622 | 2009-03-18 03:32:24 +0000 | [diff] [blame] | 223 | // id+'.'... will not append. |
| 224 | if (Tok.is(tok::numeric_constant)) |
| 225 | return GetFirstChar(PP, Tok) != '.'; |
| 226 | |
Douglas Gregor | 5cee119 | 2011-07-27 05:40:30 +0000 | [diff] [blame] | 227 | if (Tok.getIdentifierInfo() || Tok.is(tok::wide_string_literal) || |
| 228 | Tok.is(tok::utf8_string_literal) || Tok.is(tok::utf16_string_literal) || |
| 229 | Tok.is(tok::utf32_string_literal) || Tok.is(tok::wide_char_constant) || |
| 230 | Tok.is(tok::utf16_char_constant) || Tok.is(tok::utf32_char_constant)) |
Chris Lattner | d7038e1 | 2009-02-13 00:46:04 +0000 | [diff] [blame] | 231 | return true; |
Mike Stump | 1eb4433 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 232 | |
Chris Lattner | d7038e1 | 2009-02-13 00:46:04 +0000 | [diff] [blame] | 233 | // If this isn't identifier + string, we're done. |
| 234 | if (Tok.isNot(tok::char_constant) && Tok.isNot(tok::string_literal)) |
| 235 | return false; |
Mike Stump | 1eb4433 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 236 | |
Chris Lattner | d7038e1 | 2009-02-13 00:46:04 +0000 | [diff] [blame] | 237 | // Otherwise, this is a narrow character or string. If the *identifier* |
Douglas Gregor | 5cee119 | 2011-07-27 05:40:30 +0000 | [diff] [blame] | 238 | // is a literal 'L', 'u8', 'u' or 'U', avoid pasting L "foo" -> L"foo". |
| 239 | return IsIdentifierStringPrefix(PrevTok); |
Richard Smith | 99831e4 | 2012-03-06 03:21:47 +0000 | [diff] [blame] | 240 | |
Chris Lattner | d7038e1 | 2009-02-13 00:46:04 +0000 | [diff] [blame] | 241 | case tok::numeric_constant: |
| 242 | return isalnum(FirstChar) || Tok.is(tok::numeric_constant) || |
Richard Smith | 99831e4 | 2012-03-06 03:21:47 +0000 | [diff] [blame] | 243 | FirstChar == '+' || FirstChar == '-' || FirstChar == '.' || |
David Blaikie | 4e4d084 | 2012-03-11 07:00:24 +0000 | [diff] [blame] | 244 | (PP.getLangOpts().CPlusPlus0x && FirstChar == '_'); |
Chris Lattner | d7038e1 | 2009-02-13 00:46:04 +0000 | [diff] [blame] | 245 | case tok::period: // ..., .*, .1234 |
Chris Lattner | 8877321 | 2010-04-14 03:57:19 +0000 | [diff] [blame] | 246 | return (FirstChar == '.' && PrevPrevTok.is(tok::period)) || |
| 247 | isdigit(FirstChar) || |
David Blaikie | 4e4d084 | 2012-03-11 07:00:24 +0000 | [diff] [blame] | 248 | (PP.getLangOpts().CPlusPlus && FirstChar == '*'); |
Chris Lattner | d7038e1 | 2009-02-13 00:46:04 +0000 | [diff] [blame] | 249 | case tok::amp: // && |
| 250 | return FirstChar == '&'; |
| 251 | case tok::plus: // ++ |
| 252 | return FirstChar == '+'; |
| 253 | case tok::minus: // --, ->, ->* |
| 254 | return FirstChar == '-' || FirstChar == '>'; |
| 255 | case tok::slash: //, /*, // |
| 256 | return FirstChar == '*' || FirstChar == '/'; |
| 257 | case tok::less: // <<, <<=, <:, <% |
| 258 | return FirstChar == '<' || FirstChar == ':' || FirstChar == '%'; |
| 259 | case tok::greater: // >>, >>= |
| 260 | return FirstChar == '>'; |
| 261 | case tok::pipe: // || |
| 262 | return FirstChar == '|'; |
| 263 | case tok::percent: // %>, %: |
Eli Friedman | 896ccf8 | 2009-05-27 22:33:06 +0000 | [diff] [blame] | 264 | return FirstChar == '>' || FirstChar == ':'; |
Chris Lattner | d7038e1 | 2009-02-13 00:46:04 +0000 | [diff] [blame] | 265 | case tok::colon: // ::, :> |
Eli Friedman | 8849f11 | 2009-06-15 19:48:50 +0000 | [diff] [blame] | 266 | return FirstChar == '>' || |
David Blaikie | 4e4d084 | 2012-03-11 07:00:24 +0000 | [diff] [blame] | 267 | (PP.getLangOpts().CPlusPlus && FirstChar == ':'); |
Chris Lattner | d7038e1 | 2009-02-13 00:46:04 +0000 | [diff] [blame] | 268 | case tok::hash: // ##, #@, %:%: |
| 269 | return FirstChar == '#' || FirstChar == '@' || FirstChar == '%'; |
| 270 | case tok::arrow: // ->* |
David Blaikie | 4e4d084 | 2012-03-11 07:00:24 +0000 | [diff] [blame] | 271 | return PP.getLangOpts().CPlusPlus && FirstChar == '*'; |
Chris Lattner | d7038e1 | 2009-02-13 00:46:04 +0000 | [diff] [blame] | 272 | } |
| 273 | } |