https://github.com/yronglin created https://github.com/llvm/llvm-project/pull/212036
This PR add `#embed` highlighting support for clangd. <img width="412" height="142" alt="image" src="https://github.com/user-attachments/assets/e6a1a677-4c37-461a-8512-541f44327238" /> <img width="731" height="242" alt="image" src="https://github.com/user-attachments/assets/7f9339b9-d7be-4349-a6bd-b8b7e09cd036" /> >From e1b857e6cdd90c11333cbfd654961ef22c3f924e Mon Sep 17 00:00:00 2001 From: Yihan Wang <[email protected]> Date: Sun, 26 Jul 2026 00:36:59 +0800 Subject: [PATCH] [clang][tooling] Support #embed highlighting in clangd Signed-off-by: Yihan Wang <[email protected]> --- clang-tools-extra/clangd/CollectMacros.cpp | 20 ++++++ clang-tools-extra/clangd/CollectMacros.h | 6 ++ .../clangd/SemanticHighlighting.cpp | 8 +++ .../clangd/SemanticHighlighting.h | 1 + .../clangd/test/semantic-tokens-embed.test | 72 +++++++++++++++++++ .../unittests/SemanticHighlightingTests.cpp | 17 +++++ clang/lib/Frontend/DependencyFile.cpp | 3 +- .../lib/Frontend/PrintPreprocessedOutput.cpp | 8 ++- clang/lib/Lex/PPDirectives.cpp | 15 +++- clang/lib/Tooling/Syntax/Tokens.cpp | 30 ++++++++ clang/test/CoverageMapping/embed.c | 28 ++++++++ .../Preprocessor/embed_file_not_found_quote.c | 7 +- clang/unittests/Lex/PPCallbacksTest.cpp | 29 ++++++-- .../Lex/PPDependencyDirectivesTest.cpp | 3 +- clang/unittests/Tooling/Syntax/TokensTest.cpp | 30 ++++++++ 15 files changed, 261 insertions(+), 16 deletions(-) create mode 100644 clang-tools-extra/clangd/test/semantic-tokens-embed.test create mode 100644 clang/test/CoverageMapping/embed.c diff --git a/clang-tools-extra/clangd/CollectMacros.cpp b/clang-tools-extra/clangd/CollectMacros.cpp index 1e7d765f0b6f1..d03dec4a07df4 100644 --- a/clang-tools-extra/clangd/CollectMacros.cpp +++ b/clang-tools-extra/clangd/CollectMacros.cpp @@ -11,6 +11,7 @@ #include "Protocol.h" #include "SourceCode.h" #include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" #include "clang/Tooling/Syntax/Tokens.h" #include "llvm/ADT/STLExtras.h" #include <cstddef> @@ -95,6 +96,25 @@ void CollectMainFileMacros::Defined(const Token &MacroName, /*InConditionalDirective=*/true); } +void CollectMainFileMacros::EmbedDirective(SourceLocation HashLoc, StringRef, + bool, OptionalFileEntryRef, + const LexEmbedParametersResult &) { + if (!InMainFile) + return; + auto Embed = Lexer::findNextToken(HashLoc, SM, PP.getLangOpts()); + if (!Embed) + return; + + SourceLocation HashEnd = + Lexer::getLocForEndOfToken(HashLoc, 0, SM, PP.getLangOpts()); + if (HashEnd.isValid()) + Out.EmbedDirectiveTokens.push_back( + halfOpenToRange(SM, CharSourceRange::getCharRange(HashLoc, HashEnd))); + Out.EmbedDirectiveTokens.push_back( + halfOpenToRange(SM, CharSourceRange::getCharRange(Embed->getLocation(), + Embed->getEndLoc()))); +} + void CollectMainFileMacros::SourceRangeSkipped(SourceRange R, SourceLocation EndifLoc) { if (!InMainFile) diff --git a/clang-tools-extra/clangd/CollectMacros.h b/clang-tools-extra/clangd/CollectMacros.h index 20a3fc24d759c..9ef8791d4e435 100644 --- a/clang-tools-extra/clangd/CollectMacros.h +++ b/clang-tools-extra/clangd/CollectMacros.h @@ -42,6 +42,8 @@ struct MainFileMacros { // reference to an undefined macro. Store them separately, e.g. for semantic // highlighting. std::vector<MacroOccurrence> UnknownMacros; + // Ranges of the `#` and `embed` tokens in active #embed directives. + std::vector<Range> EmbedDirectiveTokens; // Ranges skipped by the preprocessor due to being inactive. std::vector<Range> SkippedRanges; }; @@ -81,6 +83,10 @@ class CollectMainFileMacros : public PPCallbacks { void Defined(const Token &MacroName, const MacroDefinition &MD, SourceRange Range) override; + void EmbedDirective(SourceLocation HashLoc, StringRef FileName, bool IsAngled, + OptionalFileEntryRef File, + const LexEmbedParametersResult &Params) override; + void SourceRangeSkipped(SourceRange R, SourceLocation EndifLoc) override; // Called when the AST build is done to disable further recording diff --git a/clang-tools-extra/clangd/SemanticHighlighting.cpp b/clang-tools-extra/clangd/SemanticHighlighting.cpp index d2d110b72011b..106931db30cd5 100644 --- a/clang-tools-extra/clangd/SemanticHighlighting.cpp +++ b/clang-tools-extra/clangd/SemanticHighlighting.cpp @@ -1116,6 +1116,9 @@ getSemanticHighlightings(ParsedAST &AST, bool IncludeInactiveRegionTokens) { for (const auto &M : AST.getMacros().UnknownMacros) AddMacro(M); + for (const Range &R : AST.getMacros().EmbedDirectiveTokens) + Builder.addToken(R, HighlightingKind::Keyword); + return std::move(Builder).collect(AST); } @@ -1169,6 +1172,8 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, HighlightingKind K) { return OS << "Bracket"; case HighlightingKind::Label: return OS << "Label"; + case HighlightingKind::Keyword: + return OS << "Keyword"; case HighlightingKind::InactiveCode: return OS << "InactiveCode"; } @@ -1200,6 +1205,7 @@ highlightingKindFromString(llvm::StringRef Name) { {"Modifier", HighlightingKind::Modifier}, {"Operator", HighlightingKind::Operator}, {"Bracket", HighlightingKind::Bracket}, + {"Keyword", HighlightingKind::Keyword}, {"InactiveCode", HighlightingKind::InactiveCode}, }; @@ -1370,6 +1376,8 @@ llvm::StringRef toSemanticTokenType(HighlightingKind Kind) { return "bracket"; case HighlightingKind::Label: return "label"; + case HighlightingKind::Keyword: + return "keyword"; case HighlightingKind::InactiveCode: return "comment"; } diff --git a/clang-tools-extra/clangd/SemanticHighlighting.h b/clang-tools-extra/clangd/SemanticHighlighting.h index 59d742b83ee52..828779bebbaa0 100644 --- a/clang-tools-extra/clangd/SemanticHighlighting.h +++ b/clang-tools-extra/clangd/SemanticHighlighting.h @@ -53,6 +53,7 @@ enum class HighlightingKind { Operator, Bracket, Label, + Keyword, // This one is different from the other kinds as it's a line style // rather than a token style. diff --git a/clang-tools-extra/clangd/test/semantic-tokens-embed.test b/clang-tools-extra/clangd/test/semantic-tokens-embed.test new file mode 100644 index 0000000000000..da2c4af3ec09d --- /dev/null +++ b/clang-tools-extra/clangd/test/semantic-tokens-embed.test @@ -0,0 +1,72 @@ +# RUN: clangd -lit-test < %s | FileCheck -strict-whitespace %s + +{"jsonrpc":"2.0","id":0,"method":"initialize","params":{ + "capabilities":{"textDocument":{"semanticTokens":{"dynamicRegistration":true}}}, + "initializationOptions":{"fallbackFlags":["-std=c23"]} +}} +# CHECK: "label", +# CHECK-NEXT: "keyword", +# CHECK-NEXT: "comment" +--- +{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{ + "uri":"test:///foo.c", + "languageId":"c", + "text":"#define P 1\nint data[] = {\n#embed \"foo.c\" prefix(P,) suffix(,P)\n};\nint after;" +}}} +--- +{"jsonrpc":"2.0","id":1,"method":"textDocument/semanticTokens/full","params":{ + "textDocument":{"uri":"test:///foo.c"} +}} +# CHECK: "id": 1, +# CHECK-NEXT: "jsonrpc": "2.0", +# CHECK-NEXT: "result": { +# CHECK-NEXT: "data": [ +# P macro definition. +# CHECK-NEXT: 0, +# CHECK-NEXT: 8, +# CHECK-NEXT: 1, +# CHECK-NEXT: 19, +# CHECK-NEXT: 131073, +# data declaration. +# CHECK-NEXT: 1, +# CHECK-NEXT: 4, +# CHECK-NEXT: 4, +# CHECK-NEXT: 0, +# CHECK-NEXT: 131075, +# # in embed directive. +# CHECK-NEXT: 1, +# CHECK-NEXT: 0, +# CHECK-NEXT: 1, +# CHECK-NEXT: 24, +# CHECK-NEXT: 0, +# embed directive keyword. +# CHECK-NEXT: 0, +# CHECK-NEXT: 1, +# CHECK-NEXT: 5, +# CHECK-NEXT: 24, +# CHECK-NEXT: 0, +# P in prefix(). +# CHECK-NEXT: 0, +# CHECK-NEXT: 21, +# CHECK-NEXT: 1, +# CHECK-NEXT: 19, +# CHECK-NEXT: 131072, +# P in suffix(). +# CHECK-NEXT: 0, +# CHECK-NEXT: 12, +# CHECK-NEXT: 1, +# CHECK-NEXT: 19, +# CHECK-NEXT: 131072, +# after declaration. +# CHECK-NEXT: 2, +# CHECK-NEXT: 4, +# CHECK-NEXT: 5, +# CHECK-NEXT: 0, +# CHECK-NEXT: 131075 +# CHECK-NEXT: ], +# CHECK-NEXT: "resultId": "1" +# CHECK-NEXT: } +--- +{"jsonrpc":"2.0","id":2,"method":"shutdown"} +--- +{"jsonrpc":"2.0","method":"exit"} diff --git a/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp b/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp index a7ebd146c297b..4eca7b8a6e8fb 100644 --- a/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp +++ b/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp @@ -1156,6 +1156,23 @@ sizeof...($TemplateParameter[[Elements]]); ~ScopeModifierMask, {"-isystemSystemSDK/"}); } +TEST(SemanticHighlighting, EmbedDirectives) { + checkHighlightings( + R"cpp( + /*error-ok*/ + int $Variable_def[[data]][] = { + $Keyword[[#]]$Keyword[[embed]] "data.bin" suffix(,) + $Keyword[[#]] /**/ $Keyword[[embed]] "empty.bin" + $Keyword[[#]]$Keyword[[embed]] "missing.bin" + }; +#if 0 +$InactiveCode[[#embed "inactive.bin"]] +#endif + )cpp", + {{"data.bin", "a"}, {"empty.bin", ""}}, ~ScopeModifierMask, + {"-std=c23", "-xc"}); +} + TEST(SemanticHighlighting, NoCrash) { // Testcases where we are just testing that computation of the // semantic tokens does not trigger a crash. diff --git a/clang/lib/Frontend/DependencyFile.cpp b/clang/lib/Frontend/DependencyFile.cpp index 00f4a54269cfa..7c005c954aba2 100644 --- a/clang/lib/Frontend/DependencyFile.cpp +++ b/clang/lib/Frontend/DependencyFile.cpp @@ -66,7 +66,8 @@ struct DepCollectorPPCallbacks : public PPCallbacks { void EmbedDirective(SourceLocation, StringRef, bool, OptionalFileEntryRef File, const LexEmbedParametersResult &) override { - assert(File && "expected to only be called when the file is found"); + if (!File) + return; StringRef FileName = llvm::sys::path::remove_leading_dotslash(File->getName()); DepCollector.maybeAddDependency(FileName, diff --git a/clang/lib/Frontend/PrintPreprocessedOutput.cpp b/clang/lib/Frontend/PrintPreprocessedOutput.cpp index 02266882c4c4a..ba21df36d7675 100644 --- a/clang/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/clang/lib/Frontend/PrintPreprocessedOutput.cpp @@ -465,17 +465,19 @@ void PrintPPOutputPPCallbacks::EmbedDirective( *OS << " prefix("; PrintToks(Params.MaybePrefixParam->Tokens); *OS << ")"; - NumToksToSkip += Params.MaybePrefixParam->Tokens.size(); + if (File) + NumToksToSkip += Params.MaybePrefixParam->Tokens.size(); } if (Params.MaybeSuffixParam) { *OS << " suffix("; PrintToks(Params.MaybeSuffixParam->Tokens); *OS << ")"; - NumToksToSkip += Params.MaybeSuffixParam->Tokens.size(); + if (File) + NumToksToSkip += Params.MaybeSuffixParam->Tokens.size(); } // We may need to skip the annotation token. - if (SkipAnnotToks) + if (File && SkipAnnotToks) NumToksToSkip++; *OS << " /* clang -E -dE */"; diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp index c161f6a03593e..c522d3f5f1c2e 100644 --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -4056,7 +4056,9 @@ void Preprocessor::HandleEmbedDirectiveImpl( size_t TokCount = Toks.size(); auto NewToks = std::make_unique<Token[]>(TokCount); llvm::copy(Toks, NewToks.get()); - EnterTokenStream(std::move(NewToks), TokCount, true, true); + EnterTokenStream(std::move(NewToks), TokCount, + /*DisableMacroExpansion=*/true, + /*IsReinject=*/false); } return; } @@ -4089,7 +4091,9 @@ void Preprocessor::HandleEmbedDirectiveImpl( } assert(CurIdx == TotalNumToks && "Calculated the incorrect number of tokens"); - EnterTokenStream(std::move(Toks), TotalNumToks, true, true); + EnterTokenStream(std::move(Toks), TotalNumToks, + /*DisableMacroExpansion=*/true, + /*IsReinject=*/false); } void Preprocessor::HandleEmbedDirective(SourceLocation HashLoc, @@ -4145,7 +4149,12 @@ void Preprocessor::HandleEmbedDirective(SourceLocation HashLoc, this->LookupEmbedFile(Filename, isAngled, /*OpenFile=*/true); if (!MaybeFileRef) { // could not find file - if (Callbacks && Callbacks->EmbedFileNotFound(Filename)) { + bool SuppressDiagnostic = + Callbacks && Callbacks->EmbedFileNotFound(Filename); + if (Callbacks) + Callbacks->EmbedDirective(HashLoc, Filename, isAngled, std::nullopt, + *Params); + if (SuppressDiagnostic) { return; } Diag(FilenameTok, diag::err_pp_file_not_found) << Filename; diff --git a/clang/lib/Tooling/Syntax/Tokens.cpp b/clang/lib/Tooling/Syntax/Tokens.cpp index 927333fda18bb..cf7f09a848c3e 100644 --- a/clang/lib/Tooling/Syntax/Tokens.cpp +++ b/clang/lib/Tooling/Syntax/Tokens.cpp @@ -15,6 +15,7 @@ #include "clang/Basic/SourceManager.h" #include "clang/Basic/TokenKinds.h" #include "clang/Lex/PPCallbacks.h" +#include "clang/Lex/PPEmbedParameters.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/Token.h" #include "llvm/ADT/ArrayRef.h" @@ -658,9 +659,36 @@ class TokenCollector::CollectPPExpansions : public PPCallbacks { Collector->Expansions[Range.getBegin()] = Range.getEnd(); LastExpansionEnd = Range.getEnd(); } + + void EmbedDirective(SourceLocation, StringRef, bool, + OptionalFileEntryRef File, + const LexEmbedParametersResult &Params) override { + if (!Collector || !File) + return; + auto Record = [&](const auto &Param) { + if (!Param) + return; + for (const clang::Token &T : Param->Tokens) + ++EmbedTokensToIgnore[T.getLocation()]; + }; + Record(Params.MaybeIfEmptyParam); + Record(Params.MaybePrefixParam); + Record(Params.MaybeSuffixParam); + } + + bool consumeIgnoredEmbedToken(const clang::Token &T) { + auto It = EmbedTokensToIgnore.find(T.getLocation()); + if (It == EmbedTokensToIgnore.end()) + return false; + if (--It->second == 0) + EmbedTokensToIgnore.erase(It); + return true; + } + // FIXME: handle directives like #pragma, #include, etc. private: TokenCollector *Collector; + llvm::DenseMap<SourceLocation, unsigned> EmbedTokensToIgnore; /// Used to detect recursive macro expansions. SourceLocation LastExpansionEnd; }; @@ -681,6 +709,8 @@ class TokenCollector::CollectPPExpansions : public PPCallbacks { TokenCollector::TokenCollector(Preprocessor &PP) : PP(PP) { // Collect the expanded token stream during preprocessing. PP.setTokenWatcher([this](const clang::Token &T) { + if (Collector->consumeIgnoredEmbedToken(T)) + return; if (T.is(tok::annot_module_name)) { auto &SM = this->PP.getSourceManager(); StringRef Text = Lexer::getSourceText( diff --git a/clang/test/CoverageMapping/embed.c b/clang/test/CoverageMapping/embed.c new file mode 100644 index 0000000000000..5c23b30a987cd --- /dev/null +++ b/clang/test/CoverageMapping/embed.c @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -std=c23 -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only %s | FileCheck %s + +int found(void) { + int data[] = { +#embed "Inputs/ends_a_scope_only" limit(1) suffix(, 2,) prefix(1,) +// found comment + + 3 + }; + return data[0]; +} + +int empty(void) { + int data[] = { +#embed "Inputs/ends_a_scope_only" limit(0) if_empty(1,) +// empty comment + + 2 + }; + return data[0]; +} + +// CHECK-LABEL: found: +// CHECK-NEXT: File 0, 3:17 -> 11:2 = #0 +// CHECK-NEXT: Skipped,File 0, 6:1 -> 7:1 = 0 +// CHECK-LABEL: empty: +// CHECK-NEXT: File 0, 13:17 -> 21:2 = #0 +// CHECK-NEXT: Skipped,File 0, 16:1 -> 17:1 = 0 diff --git a/clang/test/Preprocessor/embed_file_not_found_quote.c b/clang/test/Preprocessor/embed_file_not_found_quote.c index bf9c62b55c99e..4d9f740364fe0 100644 --- a/clang/test/Preprocessor/embed_file_not_found_quote.c +++ b/clang/test/Preprocessor/embed_file_not_found_quote.c @@ -1,4 +1,9 @@ // RUN: %clang_cc1 -std=c23 %s -E -verify +// RUN: %clang_cc1 -std=c23 %s -E -dE -verify | FileCheck %s +// expected-error@+1 {{'nfejfNejAKFe' file not found}} #embed "nfejfNejAKFe" -// expected-error@-1 {{'nfejfNejAKFe' file not found}} +int after; + +// CHECK: #embed "nfejfNejAKFe" /* clang -E -dE */ +// CHECK-NEXT: int after; diff --git a/clang/unittests/Lex/PPCallbacksTest.cpp b/clang/unittests/Lex/PPCallbacksTest.cpp index 9533fbc776e6e..e2240d98a3652 100644 --- a/clang/unittests/Lex/PPCallbacksTest.cpp +++ b/clang/unittests/Lex/PPCallbacksTest.cpp @@ -473,7 +473,8 @@ TEST_F(PPCallbacksTest, EmbedFileNotFoundChained) { llvm::MemoryBuffer::getMemBuffer(SourceText); SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(SourceBuf))); - unsigned int NumCalls = 0; + unsigned int NumNotFoundCalls = 0; + unsigned int NumDirectiveCalls = 0; HeaderSearchOptions HSOpts; TrivialModuleLoader ModLoader; PreprocessorOptions PPOpts; @@ -488,26 +489,40 @@ TEST_F(PPCallbacksTest, EmbedFileNotFoundChained) { class EmbedFileNotFoundCallbacks : public PPCallbacks { public: - unsigned int &NumCalls; + unsigned int &NumNotFoundCalls; + unsigned int &NumDirectiveCalls; - EmbedFileNotFoundCallbacks(unsigned int &NumCalls) : NumCalls(NumCalls) {} + EmbedFileNotFoundCallbacks(unsigned int &NumNotFoundCalls, + unsigned int &NumDirectiveCalls) + : NumNotFoundCalls(NumNotFoundCalls), + NumDirectiveCalls(NumDirectiveCalls) {} bool EmbedFileNotFound(StringRef FileName) override { - NumCalls++; + NumNotFoundCalls++; return true; } + + void EmbedDirective(SourceLocation, StringRef, bool, + OptionalFileEntryRef File, + const LexEmbedParametersResult &) override { + EXPECT_FALSE(File); + NumDirectiveCalls++; + } }; // Add two instances of `EmbedFileNotFoundCallbacks` to ensure the // preprocessor is using an instance of `PPChainedCallbaks`. - PP.addPPCallbacks(std::make_unique<EmbedFileNotFoundCallbacks>(NumCalls)); - PP.addPPCallbacks(std::make_unique<EmbedFileNotFoundCallbacks>(NumCalls)); + PP.addPPCallbacks(std::make_unique<EmbedFileNotFoundCallbacks>( + NumNotFoundCalls, NumDirectiveCalls)); + PP.addPPCallbacks(std::make_unique<EmbedFileNotFoundCallbacks>( + NumNotFoundCalls, NumDirectiveCalls)); // Lex source text. PP.EnterMainSourceFile(); PP.LexTokensUntilEOF(); - ASSERT_EQ(2u, NumCalls); + ASSERT_EQ(2u, NumNotFoundCalls); + ASSERT_EQ(2u, NumDirectiveCalls); ASSERT_EQ(0u, DiagConsumer->getNumErrors()); } diff --git a/clang/unittests/Lex/PPDependencyDirectivesTest.cpp b/clang/unittests/Lex/PPDependencyDirectivesTest.cpp index 6beb66d1a36f5..bd7187326e253 100644 --- a/clang/unittests/Lex/PPDependencyDirectivesTest.cpp +++ b/clang/unittests/Lex/PPDependencyDirectivesTest.cpp @@ -80,7 +80,8 @@ class EmbedCollector : public PPCallbacks { void EmbedDirective(SourceLocation, StringRef, bool, OptionalFileEntryRef File, const LexEmbedParametersResult &) override { - assert(File && "expected to only be called when the file is found"); + if (!File) + return; StringRef Filename = llvm::sys::path::remove_leading_dotslash(File->getName()); EmbeddedFiles.push_back(Filename); diff --git a/clang/unittests/Tooling/Syntax/TokensTest.cpp b/clang/unittests/Tooling/Syntax/TokensTest.cpp index 6418cc8f87d9d..68f0e53bf7512 100644 --- a/clang/unittests/Tooling/Syntax/TokensTest.cpp +++ b/clang/unittests/Tooling/Syntax/TokensTest.cpp @@ -1201,4 +1201,34 @@ TEST_F(TokenCollectorTest, CXX20ModuleImportPartition) { Kind(tok::annot_module_name), Kind(tok::semi), Kind(tok::eof))); } + +TEST_F(TokenCollectorTest, CXX26Embed) { + LangStandard = "-std=c++26"; + addFile("./data.bin", "a"); + recordTokens(R"cpp( + #define ONE 1 + #define TWO 2 + struct S { + unsigned char data[3] = { + #embed "data.bin" suffix(, TWO) prefix(ONE,) + }; + unsigned char empty[2] = { + #embed "data.bin" limit(0) if_empty(ONE, TWO) + }; + }; + )cpp"); + + EXPECT_THAT( + Buffer.expandedTokens(), + ElementsAre( + Kind(tok::kw_struct), Kind(tok::identifier), Kind(tok::l_brace), + Kind(tok::kw_unsigned), Kind(tok::kw_char), Kind(tok::identifier), + Kind(tok::l_square), Kind(tok::numeric_constant), Kind(tok::r_square), + Kind(tok::equal), Kind(tok::l_brace), Kind(tok::r_brace), + Kind(tok::semi), Kind(tok::kw_unsigned), Kind(tok::kw_char), + Kind(tok::identifier), Kind(tok::l_square), + Kind(tok::numeric_constant), Kind(tok::r_square), Kind(tok::equal), + Kind(tok::l_brace), Kind(tok::r_brace), Kind(tok::semi), + Kind(tok::r_brace), Kind(tok::semi), Kind(tok::eof))); +} } // namespace _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
