@@ -4799,6 +4799,164 @@ class SourceLocExpr final : public Expr {
47994799 friend class ASTStmtReader ;
48004800};
48014801
4802+ // / Stores data related to a single #embed directive.
4803+ struct EmbedDataStorage {
4804+ StringLiteral *BinaryData;
4805+ size_t getDataElementCount () const { return BinaryData->getByteLength (); }
4806+ };
4807+
4808+ // / Represents a reference to #emded data. By default, this references the whole
4809+ // / range. Otherwise it represents a subrange of data imported by #embed
4810+ // / directive. Needed to handle nested initializer lists with #embed directives.
4811+ // / Example:
4812+ // / struct S {
4813+ // / int x, y;
4814+ // / };
4815+ // /
4816+ // / struct T {
4817+ // / int x[2];
4818+ // / struct S s
4819+ // / };
4820+ // /
4821+ // / struct T t[] = {
4822+ // / #embed "data" // data contains 10 elements;
4823+ // / };
4824+ // /
4825+ // / The resulting semantic form of initializer list will contain (EE stands
4826+ // / for EmbedExpr):
4827+ // / { {EE(first two data elements), {EE(3rd element), EE(4th element) }},
4828+ // / { {EE(5th and 6th element), {EE(7th element), EE(8th element) }},
4829+ // / { {EE(9th and 10th element), { zeroinitializer }}}
4830+ // /
4831+ // / EmbedExpr inside of a semantic initializer list and referencing more than
4832+ // / one element can only appear for arrays of scalars.
4833+ class EmbedExpr final : public Expr {
4834+ SourceLocation EmbedKeywordLoc;
4835+ IntegerLiteral *FakeChildNode = nullptr ;
4836+ const ASTContext *Ctx = nullptr ;
4837+ EmbedDataStorage *Data;
4838+ unsigned Begin = 0 ;
4839+ unsigned NumOfElements;
4840+
4841+ public:
4842+ EmbedExpr (const ASTContext &Ctx, SourceLocation Loc, EmbedDataStorage *Data,
4843+ unsigned Begin, unsigned NumOfElements);
4844+ explicit EmbedExpr (EmptyShell Empty) : Expr(SourceLocExprClass, Empty) {}
4845+
4846+ SourceLocation getLocation () const { return EmbedKeywordLoc; }
4847+ SourceLocation getBeginLoc () const { return EmbedKeywordLoc; }
4848+ SourceLocation getEndLoc () const { return EmbedKeywordLoc; }
4849+
4850+ StringLiteral *getDataStringLiteral () const { return Data->BinaryData ; }
4851+ EmbedDataStorage *getData () const { return Data; }
4852+
4853+ unsigned getStartingElementPos () const { return Begin; }
4854+ size_t getDataElementCount () const { return NumOfElements; }
4855+
4856+ // Allows accessing every byte of EmbedExpr data and iterating over it.
4857+ // An Iterator knows the EmbedExpr that it refers to, and an offset value
4858+ // within the data.
4859+ // Dereferencing an Iterator results in construction of IntegerLiteral AST
4860+ // node filled with byte of data of the corresponding EmbedExpr within offset
4861+ // that the Iterator currently has.
4862+ template <bool Const>
4863+ class ChildElementIter
4864+ : public llvm::iterator_facade_base<
4865+ ChildElementIter<Const>, std::random_access_iterator_tag,
4866+ std::conditional_t <Const, const IntegerLiteral *,
4867+ IntegerLiteral *>> {
4868+ friend class EmbedExpr ;
4869+
4870+ EmbedExpr *EExpr = nullptr ;
4871+ unsigned long long CurOffset = ULLONG_MAX;
4872+ using BaseTy = typename ChildElementIter::iterator_facade_base;
4873+
4874+ ChildElementIter (EmbedExpr *E) : EExpr(E) {
4875+ if (E)
4876+ CurOffset = E->getStartingElementPos ();
4877+ }
4878+
4879+ public:
4880+ ChildElementIter () : CurOffset(ULLONG_MAX) {}
4881+ typename BaseTy::reference operator *() const {
4882+ assert (EExpr && CurOffset != ULLONG_MAX &&
4883+ " trying to dereference an invalid iterator" );
4884+ IntegerLiteral *N = EExpr->FakeChildNode ;
4885+ StringRef DataRef = EExpr->Data ->BinaryData ->getBytes ();
4886+ N->setValue (*EExpr->Ctx ,
4887+ llvm::APInt (N->getValue ().getBitWidth (), DataRef[CurOffset],
4888+ N->getType ()->isSignedIntegerType ()));
4889+ // We want to return a reference to the fake child node in the
4890+ // EmbedExpr, not the local variable N.
4891+ return const_cast <typename BaseTy::reference>(EExpr->FakeChildNode );
4892+ }
4893+ typename BaseTy::pointer operator ->() const { return **this ; }
4894+ using BaseTy::operator ++;
4895+ ChildElementIter &operator ++() {
4896+ assert (EExpr && " trying to increment an invalid iterator" );
4897+ assert (CurOffset != ULLONG_MAX &&
4898+ " Already at the end of what we can iterate over" );
4899+ if (++CurOffset >=
4900+ EExpr->getDataElementCount () + EExpr->getStartingElementPos ()) {
4901+ CurOffset = ULLONG_MAX;
4902+ EExpr = nullptr ;
4903+ }
4904+ return *this ;
4905+ }
4906+ bool operator ==(ChildElementIter Other) const {
4907+ return (EExpr == Other.EExpr && CurOffset == Other.CurOffset );
4908+ }
4909+ }; // class ChildElementIter
4910+
4911+ public:
4912+ using fake_child_range = llvm::iterator_range<ChildElementIter<false >>;
4913+ using const_fake_child_range = llvm::iterator_range<ChildElementIter<true >>;
4914+
4915+ fake_child_range underlying_data_elements () {
4916+ return fake_child_range (ChildElementIter<false >(this ),
4917+ ChildElementIter<false >());
4918+ }
4919+
4920+ const_fake_child_range underlying_data_elements () const {
4921+ return const_fake_child_range (
4922+ ChildElementIter<true >(const_cast <EmbedExpr *>(this )),
4923+ ChildElementIter<true >());
4924+ }
4925+
4926+ child_range children () {
4927+ return child_range (child_iterator (), child_iterator ());
4928+ }
4929+
4930+ const_child_range children () const {
4931+ return const_child_range (const_child_iterator (), const_child_iterator ());
4932+ }
4933+
4934+ static bool classof (const Stmt *T) {
4935+ return T->getStmtClass () == EmbedExprClass;
4936+ }
4937+
4938+ ChildElementIter<false > begin () { return ChildElementIter<false >(this ); }
4939+
4940+ ChildElementIter<true > begin () const {
4941+ return ChildElementIter<true >(const_cast <EmbedExpr *>(this ));
4942+ }
4943+
4944+ template <typename Call, typename ... Targs>
4945+ bool doForEachDataElement (Call &&C, unsigned &StartingIndexInArray,
4946+ Targs &&...Fargs) const {
4947+ for (auto It : underlying_data_elements ()) {
4948+ if (!std::invoke (std::forward<Call>(C), const_cast <IntegerLiteral *>(It),
4949+ StartingIndexInArray, std::forward<Targs>(Fargs)...))
4950+ return false ;
4951+ StartingIndexInArray++;
4952+ }
4953+ return true ;
4954+ }
4955+
4956+ private:
4957+ friend class ASTStmtReader ;
4958+ };
4959+
48024960// / Describes an C or C++ initializer list.
48034961// /
48044962// / InitListExpr describes an initializer list, which can be used to
0 commit comments