llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Sirraide

<details>
<summary>Changes</summary>

This patch introduces an API to Sema that takes a string of C++ code and parses 
it into an expression by calling back into the Parser. To avoid requiring Sema 
to link against the Parser, this is done via a proxy object similarly to how we 
implement template instantiation during constant evaluation.

The API in question takes a string and a map from strings to tokens; before 
parsing, the string is lexed (and preprocessed, including macro expansion), and 
the resulting list of tokens is examined for any identifier tokens which match 
any of the keys in the map; such tokens are replaced with their corresponding 
values in the map. This enables us to include tokens in the code string that  
cannot be represented in code, such as annotation tokens.

Lexing the string into tokens is done by reusing the mechanism with which we 
implement `_Pragma`.

The API is used in two places in SemaExpand.cpp to generate expressions when we 
construct and subsequently expand an iterating expansion statement.

This patch also introduces 3 new annotation tokens that are used in the 
injected code strings:

-  `tok::annot_expansion_stmt_declare_begin_end`: this token stores a 
`VarDecl*` that is the `range` variable of an iterating expansion statement and 
must be followed by two identifier tokens. It instructs the parser to declare 
the `begin` and `end` variables using `range`.

   Specifically, this token produces _two_ `DeclStmt`s of the form 
   ```c++
   auto &lt;first identifier&gt; = begin-expr; 
   auto &lt;second identifier&gt; = end-expr; 
   ```
   where `&lt;first identifier&gt;` and `&lt;second-identifer&gt;` are the 
identifier tokens that follow the annotation tokens. Unlike other 
compiler-generated `begin` and `end` variables, these variables can be found 
via name lookup (which is necessary so the subsequent code can actually 
reference them).

   This is a rather weird construct, but the reason I implemented it this way 
is that the entire range-based `for` loop code is designed around always 
creating `begin` and `end` in pairs: even if we refactor it to only create one 
of them, we'd still have to perform name lookup twice to figure out whether we 
want member or ADL `begin`/`end` (splitting that into two steps wouldn't help 
here since if we split the two declarations e.g. into two separate annotation 
tokens that are processed separately by the parser, then the parser would have 
no idea that the two are supposed to be related—unless we somehow also pass 
some extra state into the annotation tokens, but at that point that gets more 
complicated than this hack...).

   Because this token produces _two_ statements, it is handled in 
`ParseCompoundStmtBody()`.

- `tok::annot_expr`: this stores an `ExprResult`, and when the parser 
encounters it (in `ParseCastExpression()`), it simply returns that `ExprResult`.

  (We already have `tok::annot_primary_expr`, but we don't have a primary 
expression in this case so I didn't want to use that one.)

- `tok::annot_value_decl`: this stores a `ValueDecl*`, and when the parser 
encounters it (also in `ParseCastExpression()`, it creates a `DeclRefExpr` that 
points to that declaration.

  The reason we don't just create the DRE and then pass it to the parser via 
`tok::annot_expr` is that afaik there is an invariant that the same non-`Decl` 
node must not occur multiple times in the AST of any one function. The 
range-based `for` code also builds multiple DREs to `begin` and `end` for 
`begin != end`, `*begin`, etc.

Fixes #<!-- -->207778.

---

Patch is 42.12 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/208877.diff


21 Files Affected:

- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (-2) 
- (modified) clang/include/clang/Basic/TokenKinds.def (+6) 
- (modified) clang/include/clang/Lex/Lexer.h (+5-6) 
- (modified) clang/include/clang/Lex/Preprocessor.h (+5) 
- (modified) clang/include/clang/Lex/PreprocessorLexer.h (+4) 
- (modified) clang/include/clang/Parse/Parser.h (+1) 
- (modified) clang/include/clang/Sema/Sema.h (+34-1) 
- (modified) clang/lib/Lex/Lexer.cpp (+13-16) 
- (modified) clang/lib/Lex/PPLexerChange.cpp (+8) 
- (modified) clang/lib/Lex/Pragma.cpp (+9-9) 
- (modified) clang/lib/Lex/Preprocessor.cpp (+16) 
- (modified) clang/lib/Parse/ParseExpr.cpp (+9) 
- (modified) clang/lib/Parse/ParseStmt.cpp (+49) 
- (modified) clang/lib/Parse/Parser.cpp (+56-1) 
- (modified) clang/lib/Sema/SemaExpand.cpp (+57-10) 
- (modified) clang/lib/Sema/SemaStmt.cpp (+21-9) 
- (modified) clang/lib/Sema/TreeTransform.h (+3-3) 
- (modified) clang/test/AST/ast-dump-expansion-stmt.cpp (+3-8) 
- (modified) clang/test/AST/ast-print-expansion-stmts.cpp (+8-17) 
- (modified) clang/test/CodeGenCXX/cxx2c-iterating-expansion-stmt.cpp (-3) 
- (modified) clang/test/SemaCXX/cxx2c-expansion-stmts.cpp (+13-38) 


``````````diff
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 2cb79b6ba275a..a163ffd4f56da 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -176,8 +176,6 @@ def note_constexpr_assert_failed : Note<
   "assertion failed during evaluation of constant expression">;
 def err_expansion_size_expr_not_ice : Error<
   "expansion statement size is not a constant expression">;
-def err_iterating_expansion_stmt_unsupported : Error<
-  "iterating expansion statements are not yet supported">;
 
 // Semantic analysis of constant literals.
 def ext_predef_outside_function : Warning<
diff --git a/clang/include/clang/Basic/TokenKinds.def 
b/clang/include/clang/Basic/TokenKinds.def
index f07d8ebb75035..1c936e20ecdcb 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -905,6 +905,12 @@ ANNOTATION(decltype)     // annotation for a decltype 
expression,
                          // e.g., "decltype(foo.bar())"
 ANNOTATION(pack_indexing_type) // annotation for an indexed pack of type,
                               // e.g., "T...[expr]"
+ANNOTATION(value_decl) // a "ValueDecl *" to which we should build an lvalue 
DeclRefExpr
+ANNOTATION(expansion_stmt_declare_begin_end) // a "ValueDecl *" that is the 
"range"
+                                             // variable of an iterating 
expansion
+                                             // statement using which we 
should build
+                                             // declarations for "begin" and 
"end"
+ANNOTATION(expr) // an "ExprResult"
 
 // Annotation for #pragma unused(...)
 // For each argument inside the parentheses the pragma handler will produce
diff --git a/clang/include/clang/Lex/Lexer.h b/clang/include/clang/Lex/Lexer.h
index b042e5fb088fa..0b4960a966efa 100644
--- a/clang/include/clang/Lex/Lexer.h
+++ b/clang/include/clang/Lex/Lexer.h
@@ -185,12 +185,11 @@ class Lexer : public PreprocessorLexer {
   Lexer(const Lexer &) = delete;
   Lexer &operator=(const Lexer &) = delete;
 
-  /// Create_PragmaLexer: Lexer constructor - Create a new lexer object for
-  /// _Pragma expansion.  This has a variety of magic semantics that this 
method
-  /// sets up.
-  static std::unique_ptr<Lexer> Create_PragmaLexer(
-      SourceLocation SpellingLoc, SourceLocation ExpansionLocStart,
-      SourceLocation ExpansionLocEnd, unsigned TokLen, Preprocessor &PP);
+  /// CreateScratchLexer: Lexer constructor - Create a new lexer object that
+  /// places 'Code' in the scratch buffer and lexes from it.
+  static std::unique_ptr<Lexer>
+  CreateScratchLexer(StringRef Code, SourceLocation ExpansionLocStart,
+                     SourceLocation ExpansionLocEnd, Preprocessor &PP);
 
   /// getFileLoc - Return the File Location for the file we are lexing out of.
   /// The physical location encodes the location where the characters come 
from,
diff --git a/clang/include/clang/Lex/Preprocessor.h 
b/clang/include/clang/Lex/Preprocessor.h
index 413e80e7645f9..089310ce6d3a5 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -1790,6 +1790,11 @@ class Preprocessor {
   /// Lex the next token for this preprocessor.
   void Lex(Token &Result);
 
+  /// Lex all tokens in 'Code' into 'Tokens' as though we were expanding a 
macro
+  /// that expands to 'Code' at location 'Loc'.
+  bool LexTokensInString(SmallVectorImpl<Token> &Tokens, StringRef Code,
+                         SourceLocation Loc);
+
   /// Lex all tokens for this preprocessor until (and excluding) end of file.
   void LexTokensUntilEOF(std::vector<Token> *Tokens = nullptr);
 
diff --git a/clang/include/clang/Lex/PreprocessorLexer.h 
b/clang/include/clang/Lex/PreprocessorLexer.h
index d71fe708ab20a..ac3b6085a841f 100644
--- a/clang/include/clang/Lex/PreprocessorLexer.h
+++ b/clang/include/clang/Lex/PreprocessorLexer.h
@@ -52,6 +52,10 @@ class PreprocessorLexer {
   /// True after \#include; turns \<xx> or "xxx" into a tok::header_name token.
   bool ParsingFilename = false;
 
+  /// True if the preprocessor should produce an EOF token when this lexer
+  /// is done.
+  bool ProduceEOFWhenDone = false;
+
   /// True if in raw mode.
   ///
   /// Raw mode disables interpretation of tokens and is a far faster mode to
diff --git a/clang/include/clang/Parse/Parser.h 
b/clang/include/clang/Parse/Parser.h
index 892715a6dac26..a0f2fd3e89d29 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -282,6 +282,7 @@ class Parser : public CodeCompletionHandler {
   friend class PoisonSEHIdentifiersRAIIObject;
   friend class ParenBraceBracketBalancer;
   friend class BalancedDelimiterTracker;
+  class TokenInjectionHandlerImpl;
 
   Parser(Preprocessor &PP, Sema &Actions, bool SkipFunctionBodies);
   ~Parser() override;
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 6e6ca1c4aa61a..d82925576bb40 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -860,6 +860,31 @@ enum AttrName { Target, TargetClones, TargetVersion };
 
 void inferNoReturnAttr(Sema &S, Decl *D);
 
+namespace sema {
+/// Proxy class to parse a list of tokens and/or code strings.
+///
+/// This is really intended to provide access to 'Parser' without making the
+/// Sema library depend on the Parser library. We sometimes may want to 
generate
+/// implicit AST nodes, but doing so by calling various ActOnXY() functions in
+/// hopefully the right order and with the right arguments is both verbose and
+/// fragile; instead, we'd much rather write regular C++ code and just parse 
it;
+/// the APIs defined in this class facilitate this.
+class TokenInjectionHandler {
+protected:
+  TokenInjectionHandler() = default;
+
+public:
+  virtual ~TokenInjectionHandler() = default;
+
+  /// Parse 'Code' as a single expression. Any identifier token whose name is
+  /// equal to a key in 'Replacements' will be replaced with the corresponding
+  /// token in the map before parsing.
+  virtual ExprResult
+  ParseAsExpression(StringRef Code, const llvm::StringMap<Token> &Replacements,
+                    SourceLocation InjectionLoc) = 0;
+};
+} // namespace sema
+
 #ifdef __GNUC__
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wattributes"
@@ -1268,10 +1293,18 @@ class Sema final : public SemaBase {
   /// For example, user-defined classes, built-in "id" type, etc.
   Scope *TUScope;
 
+  /// Proxy object that calls into the parser to perform string injection.
+  std::unique_ptr<sema::TokenInjectionHandler> TokenInjectionHandler = nullptr;
+
   void incrementMSManglingNumber() const {
     return CurScope->incrementMSManglingNumber();
   }
 
+  void
+  setTokenInjectionHandler(std::unique_ptr<sema::TokenInjectionHandler> TIH) {
+    TokenInjectionHandler = std::move(TIH);
+  }
+
   /// Try to recover by turning the given expression into a
   /// call.  Returns true if recovery was attempted or an error was
   /// emitted; this may also leave the ExprResult invalid.
@@ -11212,7 +11245,7 @@ class Sema final : public SemaBase {
       SourceLocation CoawaitLoc,
       ArrayRef<MaterializeTemporaryExpr *> LifetimeExtendTemps,
       BuildForRangeKind Kind, bool IsConstexpr,
-      StmtResult *RebuildResult = nullptr,
+      bool AccessibleViaNameLookup = false, StmtResult *RebuildResult = 
nullptr,
       llvm::function_ref<StmtResult()> RebuildWithDereference = {},
       IdentifierInfo *BeginName = nullptr, IdentifierInfo *EndName = nullptr);
 
diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index 32ad310ca2672..b17fc2f7a094b 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -235,14 +235,10 @@ void Lexer::resetExtendedTokenMode() {
     SetCommentRetentionState(PP->getCommentRetentionState());
 }
 
-/// Create_PragmaLexer: Lexer constructor - Create a new lexer object for
-/// _Pragma expansion.  This has a variety of magic semantics that this method
-/// sets up.
+/// CreateScratchLexer: Lexer constructor - Create a new lexer object that
+/// places 'Code' in the scratch buffer and lexes from it.
 ///
-/// On entrance to this routine, TokStartLoc is a macro location which has a
-/// spelling loc that indicates the bytes to be lexed for the token and an
-/// expansion location that indicates where all lexed tokens should be
-/// "expanded from".
+/// This is used to implement _Pragma as well as string injection.
 ///
 /// TODO: It would really be nice to make _Pragma just be a wrapper around a
 /// normal lexer that remaps tokens as they fly by.  This would require making
@@ -250,11 +246,18 @@ void Lexer::resetExtendedTokenMode() {
 /// interface that could handle this stuff.  This would pull GetMappedTokenLoc
 /// out of the critical path of the lexer!
 ///
-std::unique_ptr<Lexer> Lexer::Create_PragmaLexer(
-    SourceLocation SpellingLoc, SourceLocation ExpansionLocStart,
-    SourceLocation ExpansionLocEnd, unsigned TokLen, Preprocessor &PP) {
+std::unique_ptr<Lexer>
+Lexer::CreateScratchLexer(StringRef Code, SourceLocation ExpansionLocStart,
+                          SourceLocation ExpansionLocEnd, Preprocessor &PP) {
   SourceManager &SM = PP.getSourceManager();
 
+  // Plop the string into a buffer where we can lex it.
+  Token TmpTok;
+  TmpTok.startToken();
+  PP.CreateString(Code, TmpTok);
+  SourceLocation SpellingLoc = TmpTok.getLocation();
+  unsigned TokLen = Code.size();
+
   // Create the lexer as if we were going to lex the file normally.
   FileID SpellingFID = SM.getFileID(SpellingLoc);
   llvm::MemoryBufferRef InputFile = SM.getBufferOrFake(SpellingFID);
@@ -275,12 +278,6 @@ std::unique_ptr<Lexer> Lexer::Create_PragmaLexer(
                                      ExpansionLocStart,
                                      ExpansionLocEnd, TokLen);
 
-  // Ensure that the lexer thinks it is inside a directive, so that end \n will
-  // return an EOD token.
-  L->ParsingPreprocessorDirective = true;
-
-  // This lexer really is for _Pragma.
-  L->Is_PragmaLexer = true;
   return L;
 }
 
diff --git a/clang/lib/Lex/PPLexerChange.cpp b/clang/lib/Lex/PPLexerChange.cpp
index b44bf2cd3c253..74e800f83b2a4 100644
--- a/clang/lib/Lex/PPLexerChange.cpp
+++ b/clang/lib/Lex/PPLexerChange.cpp
@@ -488,9 +488,17 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool 
isEndOfMacro) {
             SourceMgr.getFileEntryForID(CurPPLexer->getFileID())))
       FoundPCHThroughHeader = true;
 
+    bool ShouldProduceEOF = CurLexer && CurLexer->ProduceEOFWhenDone;
+
     // We're done with the #included file.
     RemoveTopOfLexerStack();
 
+    if (ShouldProduceEOF) {
+      Result.startToken();
+      Result.setKind(tok::eof);
+      return true;
+    }
+
     // Propagate info about start-of-line/leading white-space/etc.
     PropagateLineStartLeadingSpaceInfo(Result);
 
diff --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp
index 9b48a45ade668..e9a4582430b25 100644
--- a/clang/lib/Lex/Pragma.cpp
+++ b/clang/lib/Lex/Pragma.cpp
@@ -279,17 +279,17 @@ void Preprocessor::Handle_Pragma(Token &Tok) {
   // The _Pragma is lexically sound.  Destringize according to C11 6.10.9.1.
   prepare_PragmaString(StrVal);
 
-  // Plop the string (including the newline and trailing null) into a buffer
-  // where we can lex it.
-  Token TmpTok;
-  TmpTok.startToken();
-  CreateString(StrVal, TmpTok);
-  SourceLocation TokLoc = TmpTok.getLocation();
-
   // Make and enter a lexer object so that we lex and expand the tokens just
   // like any others.
-  std::unique_ptr<Lexer> TL = Lexer::Create_PragmaLexer(
-      TokLoc, PragmaLoc, RParenLoc, StrVal.size(), *this);
+  std::unique_ptr<Lexer> TL =
+      Lexer::CreateScratchLexer(StrVal, PragmaLoc, RParenLoc, *this);
+
+  // Ensure that the lexer thinks it is inside a directive, so that end \n will
+  // return an EOD token.
+  TL->ParsingPreprocessorDirective = true;
+
+  // This lexer really is for _Pragma.
+  TL->Is_PragmaLexer = true;
 
   EnterSourceFileWithLexer(std::move(TL), nullptr);
 
diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp
index 1625d5918e8f5..9a0311e4879ec 100644
--- a/clang/lib/Lex/Preprocessor.cpp
+++ b/clang/lib/Lex/Preprocessor.cpp
@@ -573,6 +573,22 @@ Module *Preprocessor::getCurrentModuleImplementation() {
   return getHeaderSearchInfo().lookupModule(getLangOpts().ModuleName);
 }
 
+bool Preprocessor::LexTokensInString(SmallVectorImpl<Token> &Tokens,
+                                     StringRef Code, SourceLocation Loc) {
+  std::unique_ptr<Lexer> L = Lexer::CreateScratchLexer(Code, Loc, Loc, *this);
+  L->ProduceEOFWhenDone = true; // Stop lexing once 'L' is done.
+  EnterSourceFileWithLexer(std::move(L), nullptr);
+  for (;;) {
+    Token Tok;
+    Lex(Tok);
+    if (Tok.is(tok::unknown))
+      return true;
+    if (Tok.is(tok::eof))
+      return false;
+    Tokens.push_back(Tok);
+  }
+}
+
 
//===----------------------------------------------------------------------===//
 // Preprocessor Initialization Methods
 
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index 74209f579776d..36c9e9075543a 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -849,6 +849,7 @@ Parser::ParseCastExpression(CastParseKind ParseKind, bool 
isAddressOfOperand,
     Res = Actions.ActOnCXXNullPtrLiteral(ConsumeToken());
     break;
 
+  case tok::annot_expr:
   case tok::annot_primary_expr:
   case tok::annot_overload_set:
     Res = getExprAnnotation(Tok);
@@ -876,6 +877,14 @@ Parser::ParseCastExpression(CastParseKind ParseKind, bool 
isAddressOfOperand,
                                NotPrimaryExpression);
   }
 
+  case tok::annot_value_decl: {
+    auto *VD = static_cast<ValueDecl *>(Tok.getAnnotationValue());
+    SourceLocation Loc = Tok.getLocation();
+    ConsumeAnnotationToken();
+    return Actions.BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(),
+                                    VK_LValue, Loc);
+  }
+
   case tok::kw___super:
   case tok::kw_decltype:
     // Annotate the token and tail recurse.
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index df01c91c065a1..5d3a4e268fdcd 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -1202,6 +1202,55 @@ StmtResult Parser::ParseCompoundStatementBody(bool 
isStmtExpr) {
       continue;
     }
 
+    // Annotation token that tells the parser to build the 'begin' and 'end'
+    // declarations for an iterating expansion statement; this is used inside
+    // the lambda that computes the expansion size (see also
+    // Sema::ComputeExpansionSize()).
+    //
+    // The annotation token is followed by 2 identifier tokens, which indicate
+    // the variable names for the begin and end variable, respectively.
+    //
+    // We handle this here because this results in *two* statements, not one,
+    // and moreover, this annotation token shouldn't appear in any other 
context
+    // anyway.
+    //
+    // The reason this is a single annotation token is that the code that 
builds
+    // 'begin' and 'end' only supports building both at once.
+    if (Tok.is(tok::annot_expansion_stmt_declare_begin_end)) {
+      auto *RangeVarDecl = static_cast<VarDecl *>(Tok.getAnnotationValue());
+      ConsumeAnnotationToken();
+
+      assert(Tok.is(tok::identifier));
+      IdentifierInfo *BeginName = Tok.getIdentifierInfo();
+      ConsumeToken();
+
+      assert(Tok.is(tok::identifier));
+      IdentifierInfo *EndName = Tok.getIdentifierInfo();
+      ConsumeToken();
+
+      SourceLocation Loc = RangeVarDecl->getBeginLoc();
+      Sema::ForRangeBeginEndInfo Info = Actions.BuildCXXForRangeBeginEndVars(
+          getCurScope(), RangeVarDecl, RangeVarDecl->getBeginLoc(),
+          /*CoawaitLoc=*/{},
+          /*LifetimeExtendTemps=*/{}, Sema::BFRK_Build, /*Constexpr=*/false,
+          /*AccessibleViaNameLookup=*/true,
+          /*RebuildResult=*/nullptr, /*RebuildWithDereference=*/nullptr,
+          BeginName, EndName);
+      if (!Info.isValid())
+        continue;
+
+      StmtResult BeginStmt = Actions.ActOnDeclStmt(
+          Actions.ConvertDeclToDeclGroup(Info.BeginVar), Loc, Loc);
+      StmtResult EndStmt = Actions.ActOnDeclStmt(
+          Actions.ConvertDeclToDeclGroup(Info.EndVar), Loc, Loc);
+      if (BeginStmt.isInvalid() || EndStmt.isInvalid())
+        continue;
+
+      Stmts.push_back(BeginStmt.get());
+      Stmts.push_back(EndStmt.get());
+      continue;
+    }
+
     if (ConsumeNullStmt(Stmts))
       continue;
 
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 5e1fd4df1a3f0..fa7052ab2beed 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -48,6 +48,59 @@ class ActionCommentHandler : public CommentHandler {
 };
 } // end anonymous namespace
 
+class Parser::TokenInjectionHandlerImpl : public sema::TokenInjectionHandler {
+  Parser &P;
+
+public:
+  explicit TokenInjectionHandlerImpl(Parser &P) : P{P} {}
+
+  ExprResult ParseAsExpression(StringRef Code,
+                               const llvm::StringMap<Token> &Replacements,
+                               SourceLocation InjectionLoc) override {
+    // Collect tokens.
+    SmallVector<Token> Tokens;
+    if (P.PP.LexTokensInString(Tokens, Code, InjectionLoc))
+      return ExprError();
+
+    for (Token &Tok : Tokens) {
+      if (Tok.is(tok::identifier)) {
+        auto It = Replacements.find(Tok.getIdentifierInfo()->getName());
+        if (It != Replacements.end())
+          Tok = It->getValue();
+      }
+    }
+
+    // Add an EOF token so we know when to stop.
+    char EofMarker{};
+    Token &EofToken = Tokens.emplace_back();
+    EofToken.startToken();
+    EofToken.setKind(tok::eof);
+    EofToken.setEofData(&EofMarker);
+
+    // Start parsing the tokens; we need to save the current token so we
+    // don't lose it, and consume it since EnterTokenStream() doesn't change
+    // the current token.
+    //
+    // Disable macro expansion since that was already done as part of the call
+    // to LexTokensInString() above; 'IsReinjected' is for phase 4 tokens, so
+    // we don't want that either here.
+    SaveAndRestore SaveCurTok{P.Tok};
+    P.PP.EnterTokenStream(Tokens, /*DisableMacroExpansion=*/true,
+                          /*IsReinjected=*/false);
+    P.ConsumeAnyToken();
+    ExprResult Res = P.ParseExpression();
+
+    // We should have parsed exactly one expression; if we still have tokens
+    // left, then there was probably an error; don't diagnose this and just
+    // skip them.
+    while (P.Tok.isNot(tok::eof))
+      P.ConsumeAnyToken();
+
+    assert(P.Tok.getEofData() == &EofMarker);
+    return Res;
+  }
+};
+
 IdentifierInfo *Parser::getSEHExceptKeyword() {
   // __except is accepted as a (contextual) keyword
   if (!Ident__except && (getLangOpts().MicrosoftExt || getLangOpts().Borland))
@@ -74,6 +127,8 @@ Parser::Parser(Preprocessor &pp, Sema &actions, bool 
skipFunctionBodies)
   // destructor.
   initializePragmaHandlers();
 
+  Actions.setTokenInjectionHandler(
+      std::make_unique<TokenInjectionHandlerImpl>(*this));
   CommentSemaHandler.reset(new ActionCommentHandler(actions));
   PP.addCommentHandler(CommentSemaHandler.get());
 
@@ -482,7 +537,7 @@ Parser::~Parser() {
   resetPragmaHandlers();
 
   PP.removeCommentHandler(CommentSemaHandler.get());
-
+  Actions.setTokenInjectionHandler(nullptr);
   PP.clearCodeCompletionHandler();
 
   DestroyTemplateIds();
diff --git a/clang/lib/Sema/SemaExpand.cpp b/clang/lib/Sema/SemaExpand.cpp
index 9d8893dbdb731..4af60b0a51ed7 100644
--- a/clang/lib/Sema/SemaExpand.cpp
+++ b/clang/lib/Sema/SemaExpand.cpp
@@ -76,6 +76,26 @@ static auto InitListContainsPack(const InitListExpr *ILE) {
                       [](const Expr *E) { return isa<PackExpansionExpr>(E); });
 }
 
+static Token CreateValueDeclAnnotToken(ValueDecl *D, SourceLocation Loc) {
+  Token Tok;
+  Tok.startToken();
+  Tok.setKind(tok::annot_value_decl);
+  Tok.setAnnotationValue(D);
+  Tok.setAnnotationEndLoc(Loc);
+  Tok.setLocation(Loc);
+  return Tok;
+}
+
+static Token CreateExprAnnotToken(Expr *E, SourceLocation Loc) {
+  Token Tok;
+  Tok.startToken();
+  Tok.setKind(tok::annot_expr);
+  Tok.setAnnotationValue(ExprResult(E...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/208877
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to