[clang] [clang-tools-extra] Reland [clang][Sema, Lex, Parse] Preprocessor embed in C and C++ (PR #95802)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Jun 17 08:26:52 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-driver
Author: Mariya Podchishchaeva (Fznamznon)
<details>
<summary>Changes</summary>
This commit implements the entirety of the now-accepted [N3017 -Preprocessor Embed](https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3017.htm) and its sister C++ paper [p1967](https://wg21.link/p1967). It implements everything in the specification, and includes an implementation that drastically improves the time it takes to embed data in specific scenarios (the initialization of character type arrays). The mechanisms used to do this are used under the "as-if" rule, and in general when the system cannot detect it is initializing an array object in a variable declaration, will generate EmbedExpr AST node which will be expanded by AST consumers (CodeGen or constant expression evaluators) or expand embed directive as a comma expression.
This reverts commit https://github.com/llvm/llvm-project/commit/682d461d5a231cee54d65910e6341769419a67d7.
---------
Co-authored-by: The Phantom Derpstorm <phdofthehouse@<!-- -->gmail.com>
Co-authored-by: Aaron Ballman <aaron@<!-- -->aaronballman.com>
Co-authored-by: cor3ntin <corentinjabot@<!-- -->gmail.com>
Co-authored-by: H. Vetinari <h.vetinari@<!-- -->gmx.com>
---
Patch is 184.69 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/95802.diff
96 Files Affected:
- (modified) clang-tools-extra/test/pp-trace/pp-trace-macro.cpp (+9)
- (modified) clang/docs/LanguageExtensions.rst (+24)
- (modified) clang/include/clang/AST/Expr.h (+158)
- (modified) clang/include/clang/AST/RecursiveASTVisitor.h (+5)
- (modified) clang/include/clang/AST/TextNodeDumper.h (+1)
- (modified) clang/include/clang/Basic/DiagnosticCommonKinds.td (+3)
- (modified) clang/include/clang/Basic/DiagnosticLexKinds.td (+12)
- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (-2)
- (modified) clang/include/clang/Basic/FileManager.h (+7-4)
- (modified) clang/include/clang/Basic/StmtNodes.td (+1)
- (modified) clang/include/clang/Basic/TokenKinds.def (+6)
- (modified) clang/include/clang/Driver/Options.td (+6)
- (modified) clang/include/clang/Frontend/PreprocessorOutputOptions.h (+3)
- (modified) clang/include/clang/Lex/PPCallbacks.h (+54)
- (added) clang/include/clang/Lex/PPDirectiveParameter.h (+33)
- (added) clang/include/clang/Lex/PPEmbedParameters.h (+94)
- (modified) clang/include/clang/Lex/Preprocessor.h (+67-2)
- (modified) clang/include/clang/Lex/PreprocessorOptions.h (+3)
- (modified) clang/include/clang/Parse/Parser.h (+3)
- (modified) clang/include/clang/Sema/Sema.h (+4)
- (modified) clang/include/clang/Serialization/ASTBitCodes.h (+3)
- (modified) clang/lib/AST/Expr.cpp (+12)
- (modified) clang/lib/AST/ExprClassification.cpp (+5)
- (modified) clang/lib/AST/ExprConstant.cpp (+58-5)
- (modified) clang/lib/AST/Interp/ByteCodeExprGen.cpp (+18-3)
- (modified) clang/lib/AST/Interp/ByteCodeExprGen.h (+1)
- (modified) clang/lib/AST/ItaniumMangle.cpp (+1)
- (modified) clang/lib/AST/StmtPrinter.cpp (+4)
- (modified) clang/lib/AST/StmtProfile.cpp (+2)
- (modified) clang/lib/AST/TextNodeDumper.cpp (+5)
- (modified) clang/lib/Basic/FileManager.cpp (+6-1)
- (modified) clang/lib/Basic/IdentifierTable.cpp (+3-2)
- (modified) clang/lib/CodeGen/CGExprAgg.cpp (+32-8)
- (modified) clang/lib/CodeGen/CGExprConstant.cpp (+93-25)
- (modified) clang/lib/CodeGen/CGExprScalar.cpp (+7)
- (modified) clang/lib/Driver/ToolChains/Clang.cpp (+5-1)
- (modified) clang/lib/Frontend/CompilerInvocation.cpp (+8)
- (modified) clang/lib/Frontend/DependencyFile.cpp (+25)
- (modified) clang/lib/Frontend/DependencyGraph.cpp (+23-1)
- (modified) clang/lib/Frontend/InitPreprocessor.cpp (+8)
- (modified) clang/lib/Frontend/PrintPreprocessedOutput.cpp (+115-7)
- (modified) clang/lib/Lex/PPDirectives.cpp (+474-2)
- (modified) clang/lib/Lex/PPExpressions.cpp (+36-13)
- (modified) clang/lib/Lex/PPMacroExpansion.cpp (+111)
- (modified) clang/lib/Lex/TokenConcatenation.cpp (+4-1)
- (modified) clang/lib/Parse/ParseExpr.cpp (+36-1)
- (modified) clang/lib/Parse/ParseInit.cpp (+30)
- (modified) clang/lib/Parse/ParseTemplate.cpp (+29-12)
- (modified) clang/lib/Sema/SemaExceptionSpec.cpp (+1)
- (modified) clang/lib/Sema/SemaExpr.cpp (+12-3)
- (modified) clang/lib/Sema/SemaInit.cpp (+100-13)
- (modified) clang/lib/Sema/TreeTransform.h (+5)
- (modified) clang/lib/Serialization/ASTReaderStmt.cpp (+14)
- (modified) clang/lib/Serialization/ASTWriterStmt.cpp (+10)
- (modified) clang/lib/StaticAnalyzer/Core/ExprEngine.cpp (+4)
- (added) clang/test/C/C2x/Inputs/bits.bin (+1)
- (added) clang/test/C/C2x/Inputs/boop.h (+1)
- (added) clang/test/C/C2x/Inputs/i.dat (+1)
- (added) clang/test/C/C2x/Inputs/jump.wav (+1)
- (added) clang/test/C/C2x/Inputs/s.dat (+1)
- (added) clang/test/C/C2x/n3017.c (+216)
- (added) clang/test/Preprocessor/Inputs/jk.txt (+1)
- (added) clang/test/Preprocessor/Inputs/media/art.txt (+9)
- (added) clang/test/Preprocessor/Inputs/media/empty ()
- (added) clang/test/Preprocessor/Inputs/null_byte.bin ()
- (added) clang/test/Preprocessor/Inputs/numbers.txt (+1)
- (added) clang/test/Preprocessor/Inputs/single_byte.txt (+1)
- (added) clang/test/Preprocessor/embed___has_embed.c (+60)
- (added) clang/test/Preprocessor/embed___has_embed_parsing_errors.c (+240)
- (added) clang/test/Preprocessor/embed___has_embed_supported.c (+24)
- (added) clang/test/Preprocessor/embed_art.c (+104)
- (added) clang/test/Preprocessor/embed_codegen.cpp (+84)
- (added) clang/test/Preprocessor/embed_constexpr.cpp (+97)
- (added) clang/test/Preprocessor/embed_dependencies.c (+20)
- (added) clang/test/Preprocessor/embed_ext_compat_diags.c (+16)
- (added) clang/test/Preprocessor/embed_feature_test.cpp (+7)
- (added) clang/test/Preprocessor/embed_file_not_found_chevron.c (+4)
- (added) clang/test/Preprocessor/embed_file_not_found_quote.c (+4)
- (added) clang/test/Preprocessor/embed_init.c (+29)
- (added) clang/test/Preprocessor/embed_parameter_if_empty.c (+24)
- (added) clang/test/Preprocessor/embed_parameter_limit.c (+94)
- (added) clang/test/Preprocessor/embed_parameter_offset.c (+89)
- (added) clang/test/Preprocessor/embed_parameter_prefix.c (+38)
- (added) clang/test/Preprocessor/embed_parameter_suffix.c (+39)
- (added) clang/test/Preprocessor/embed_parameter_unrecognized.c (+9)
- (added) clang/test/Preprocessor/embed_parsing_errors.c (+130)
- (added) clang/test/Preprocessor/embed_path_chevron.c (+8)
- (added) clang/test/Preprocessor/embed_path_quote.c (+8)
- (added) clang/test/Preprocessor/embed_preprocess_to_file.c (+39)
- (added) clang/test/Preprocessor/embed_single_entity.c (+7)
- (added) clang/test/Preprocessor/embed_weird.cpp (+98)
- (modified) clang/test/Preprocessor/init-aarch64.c (+3)
- (modified) clang/test/Preprocessor/init.c (+3)
- (added) clang/test/Preprocessor/single_byte.txt (+1)
- (modified) clang/tools/libclang/CXCursor.cpp (+1)
- (modified) clang/www/c_status.html (+1-1)
``````````diff
diff --git a/clang-tools-extra/test/pp-trace/pp-trace-macro.cpp b/clang-tools-extra/test/pp-trace/pp-trace-macro.cpp
index 1d85607e86b7f..7c2a231101070 100644
--- a/clang-tools-extra/test/pp-trace/pp-trace-macro.cpp
+++ b/clang-tools-extra/test/pp-trace/pp-trace-macro.cpp
@@ -31,6 +31,15 @@ X
// CHECK: MacroNameTok: __STDC_UTF_32__
// CHECK-NEXT: MacroDirective: MD_Define
// CHECK: - Callback: MacroDefined
+// CHECK-NEXT: MacroNameTok: __STDC_EMBED_NOT_FOUND__
+// CHECK-NEXT: MacroDirective: MD_Define
+// CHECK: - Callback: MacroDefined
+// CHECK-NEXT: MacroNameTok: __STDC_EMBED_FOUND__
+// CHECK-NEXT: MacroDirective: MD_Define
+// CHECK: - Callback: MacroDefined
+// CHECK-NEXT: MacroNameTok: __STDC_EMBED_EMPTY__
+// CHECK-NEXT: MacroDirective: MD_Define
+// CHECK: - Callback: MacroDefined
// CHECK: - Callback: MacroDefined
// CHECK-NEXT: MacroNameTok: MACRO
// CHECK-NEXT: MacroDirective: MD_Define
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 92e6025c95a8c..9830b35faae12 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -1502,6 +1502,7 @@ Attributes on Structured Bindings __cpp_structured_bindings C+
Designated initializers (N494) C99 C89
Array & element qualification (N2607) C23 C89
Attributes (N2335) C23 C89
+``#embed`` (N3017) C23 C89, C++
============================================ ================================ ============= =============
Type Trait Primitives
@@ -5664,3 +5665,26 @@ Compiling different TUs depending on these flags (including use of
``std::hardware_destructive_interference``) with different compilers, macro
definitions, or architecture flags will lead to ODR violations and should be
avoided.
+
+``#embed`` Parameters
+=====================
+
+``clang::offset``
+-----------------
+The ``clang::offset`` embed parameter may appear zero or one time in the
+embed parameter sequence. Its preprocessor argument clause shall be present and
+have the form:
+
+..code-block: text
+
+ ( constant-expression )
+
+and shall be an integer constant expression. The integer constant expression
+shall not evaluate to a value less than 0. The token ``defined`` shall not
+appear within the constant expression.
+
+The offset will be used when reading the contents of the embedded resource to
+specify the starting offset to begin embedding from. The resources is treated
+as being empty if the specified offset is larger than the number of bytes in
+the resource. The offset will be applied *before* any ``limit`` parameters are
+applied.
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index f2bf667636dc9..3bc8cae4d8c86 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -4799,6 +4799,164 @@ class SourceLocExpr final : public Expr {
friend class ASTStmtReader;
};
+/// Stores data related to a single #embed directive.
+struct EmbedDataStorage {
+ StringLiteral *BinaryData;
+ size_t getDataElementCount() const { return BinaryData->getByteLength(); }
+};
+
+/// Represents a reference to #emded data. By default, this references the whole
+/// range. Otherwise it represents a subrange of data imported by #embed
+/// directive. Needed to handle nested initializer lists with #embed directives.
+/// Example:
+/// struct S {
+/// int x, y;
+/// };
+///
+/// struct T {
+/// int x[2];
+/// struct S s
+/// };
+///
+/// struct T t[] = {
+/// #embed "data" // data contains 10 elements;
+/// };
+///
+/// The resulting semantic form of initializer list will contain (EE stands
+/// for EmbedExpr):
+/// { {EE(first two data elements), {EE(3rd element), EE(4th element) }},
+/// { {EE(5th and 6th element), {EE(7th element), EE(8th element) }},
+/// { {EE(9th and 10th element), { zeroinitializer }}}
+///
+/// EmbedExpr inside of a semantic initializer list and referencing more than
+/// one element can only appear for arrays of scalars.
+class EmbedExpr final : public Expr {
+ SourceLocation EmbedKeywordLoc;
+ IntegerLiteral *FakeChildNode = nullptr;
+ const ASTContext *Ctx = nullptr;
+ EmbedDataStorage *Data;
+ unsigned Begin = 0;
+ unsigned NumOfElements;
+
+public:
+ EmbedExpr(const ASTContext &Ctx, SourceLocation Loc, EmbedDataStorage *Data,
+ unsigned Begin, unsigned NumOfElements);
+ explicit EmbedExpr(EmptyShell Empty) : Expr(SourceLocExprClass, Empty) {}
+
+ SourceLocation getLocation() const { return EmbedKeywordLoc; }
+ SourceLocation getBeginLoc() const { return EmbedKeywordLoc; }
+ SourceLocation getEndLoc() const { return EmbedKeywordLoc; }
+
+ StringLiteral *getDataStringLiteral() const { return Data->BinaryData; }
+ EmbedDataStorage *getData() const { return Data; }
+
+ unsigned getStartingElementPos() const { return Begin; }
+ size_t getDataElementCount() const { return NumOfElements; }
+
+ // Allows accessing every byte of EmbedExpr data and iterating over it.
+ // An Iterator knows the EmbedExpr that it refers to, and an offset value
+ // within the data.
+ // Dereferencing an Iterator results in construction of IntegerLiteral AST
+ // node filled with byte of data of the corresponding EmbedExpr within offset
+ // that the Iterator currently has.
+ template <bool Const>
+ class ChildElementIter
+ : public llvm::iterator_facade_base<
+ ChildElementIter<Const>, std::random_access_iterator_tag,
+ std::conditional_t<Const, const IntegerLiteral *,
+ IntegerLiteral *>> {
+ friend class EmbedExpr;
+
+ EmbedExpr *EExpr = nullptr;
+ unsigned long long CurOffset = ULLONG_MAX;
+ using BaseTy = typename ChildElementIter::iterator_facade_base;
+
+ ChildElementIter(EmbedExpr *E) : EExpr(E) {
+ if (E)
+ CurOffset = E->getStartingElementPos();
+ }
+
+ public:
+ ChildElementIter() : CurOffset(ULLONG_MAX) {}
+ typename BaseTy::reference operator*() const {
+ assert(EExpr && CurOffset != ULLONG_MAX &&
+ "trying to dereference an invalid iterator");
+ IntegerLiteral *N = EExpr->FakeChildNode;
+ StringRef DataRef = EExpr->Data->BinaryData->getBytes();
+ N->setValue(*EExpr->Ctx,
+ llvm::APInt(N->getValue().getBitWidth(), DataRef[CurOffset],
+ N->getType()->isSignedIntegerType()));
+ // We want to return a reference to the fake child node in the
+ // EmbedExpr, not the local variable N.
+ return const_cast<typename BaseTy::reference>(EExpr->FakeChildNode);
+ }
+ typename BaseTy::pointer operator->() const { return **this; }
+ using BaseTy::operator++;
+ ChildElementIter &operator++() {
+ assert(EExpr && "trying to increment an invalid iterator");
+ assert(CurOffset != ULLONG_MAX &&
+ "Already at the end of what we can iterate over");
+ if (++CurOffset >=
+ EExpr->getDataElementCount() + EExpr->getStartingElementPos()) {
+ CurOffset = ULLONG_MAX;
+ EExpr = nullptr;
+ }
+ return *this;
+ }
+ bool operator==(ChildElementIter Other) const {
+ return (EExpr == Other.EExpr && CurOffset == Other.CurOffset);
+ }
+ }; // class ChildElementIter
+
+public:
+ using fake_child_range = llvm::iterator_range<ChildElementIter<false>>;
+ using const_fake_child_range = llvm::iterator_range<ChildElementIter<true>>;
+
+ fake_child_range underlying_data_elements() {
+ return fake_child_range(ChildElementIter<false>(this),
+ ChildElementIter<false>());
+ }
+
+ const_fake_child_range underlying_data_elements() const {
+ return const_fake_child_range(
+ ChildElementIter<true>(const_cast<EmbedExpr *>(this)),
+ ChildElementIter<true>());
+ }
+
+ child_range children() {
+ return child_range(child_iterator(), child_iterator());
+ }
+
+ const_child_range children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == EmbedExprClass;
+ }
+
+ ChildElementIter<false> begin() { return ChildElementIter<false>(this); }
+
+ ChildElementIter<true> begin() const {
+ return ChildElementIter<true>(const_cast<EmbedExpr *>(this));
+ }
+
+ template <typename Call, typename... Targs>
+ bool doForEachDataElement(Call &&C, unsigned &StartingIndexInArray,
+ Targs &&...Fargs) const {
+ for (auto It : underlying_data_elements()) {
+ if (!std::invoke(std::forward<Call>(C), const_cast<IntegerLiteral *>(It),
+ StartingIndexInArray, std::forward<Targs>(Fargs)...))
+ return false;
+ StartingIndexInArray++;
+ }
+ return true;
+ }
+
+private:
+ friend class ASTStmtReader;
+};
+
/// Describes an C or C++ initializer list.
///
/// InitListExpr describes an initializer list, which can be used to
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index aa55e2e7e8718..2785afd59bf21 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -2864,6 +2864,11 @@ DEF_TRAVERSE_STMT(ShuffleVectorExpr, {})
DEF_TRAVERSE_STMT(ConvertVectorExpr, {})
DEF_TRAVERSE_STMT(StmtExpr, {})
DEF_TRAVERSE_STMT(SourceLocExpr, {})
+DEF_TRAVERSE_STMT(EmbedExpr, {
+ for (IntegerLiteral *IL : S->underlying_data_elements()) {
+ TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(IL);
+ }
+})
DEF_TRAVERSE_STMT(UnresolvedLookupExpr, {
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h
index abfafcaef271b..39dd1f515c9eb 100644
--- a/clang/include/clang/AST/TextNodeDumper.h
+++ b/clang/include/clang/AST/TextNodeDumper.h
@@ -409,6 +409,7 @@ class TextNodeDumper
void VisitHLSLBufferDecl(const HLSLBufferDecl *D);
void VisitOpenACCConstructStmt(const OpenACCConstructStmt *S);
void VisitOpenACCLoopConstruct(const OpenACCLoopConstruct *S);
+ void VisitEmbedExpr(const EmbedExpr *S);
};
} // namespace clang
diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td
index 1e44bc4ad09b6..de758cbe679dc 100644
--- a/clang/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td
@@ -275,6 +275,9 @@ def err_too_large_for_fixed_point : Error<
def err_unimplemented_conversion_with_fixed_point_type : Error<
"conversion between fixed point and %0 is not yet supported">;
+def err_requires_positive_value : Error<
+ "%select{invalid value '%0'; must be positive|value '%0' is too large}1">;
+
// SEH
def err_seh_expected_handler : Error<
"expected '__except' or '__finally' block">;
diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td
index 25fbfe83fa2bc..12d7b8c0205ee 100644
--- a/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -436,6 +436,14 @@ def warn_cxx23_compat_warning_directive : Warning<
def warn_c23_compat_warning_directive : Warning<
"#warning is incompatible with C standards before C23">,
InGroup<CPre23Compat>, DefaultIgnore;
+def ext_pp_embed_directive : ExtWarn<
+ "#embed is a %select{C23|Clang}0 extension">,
+ InGroup<C23>;
+def warn_compat_pp_embed_directive : Warning<
+ "#embed is incompatible with C standards before C23">,
+ InGroup<CPre23Compat>, DefaultIgnore;
+def err_pp_embed_dup_params : Error<
+ "cannot specify parameter '%0' twice in the same '#embed' directive">;
def ext_pp_extra_tokens_at_eol : ExtWarn<
"extra tokens at end of #%0 directive">, InGroup<ExtraTokens>;
@@ -505,6 +513,8 @@ def err_pp_invalid_directive : Error<
"invalid preprocessing directive%select{|, did you mean '#%1'?}0">;
def warn_pp_invalid_directive : Warning<
err_pp_invalid_directive.Summary>, InGroup<DiagGroup<"unknown-directives">>;
+def err_pp_unknown_parameter : Error<
+ "unknown%select{ | embed}0 preprocessor parameter '%1'">;
def err_pp_directive_required : Error<
"%0 must be used within a preprocessing directive">;
def err_pp_file_not_found : Error<"'%0' file not found">, DefaultFatal;
@@ -719,6 +729,8 @@ def err_pp_module_build_missing_end : Error<
"no matching '#pragma clang module endbuild' for this '#pragma clang module build'">;
def err_defined_macro_name : Error<"'defined' cannot be used as a macro name">;
+def err_defined_in_pp_embed : Error<
+ "'defined' cannot appear within this context">;
def err_paste_at_start : Error<
"'##' cannot appear at start of macro expansion">;
def err_paste_at_end : Error<"'##' cannot appear at end of macro expansion">;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 9b8f5b7e80e7e..833e8b51c0257 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1097,8 +1097,6 @@ def note_surrounding_namespace_starts_here : Note<
"surrounding namespace with visibility attribute starts here">;
def err_pragma_loop_invalid_argument_type : Error<
"invalid argument of type %0; expected an integer type">;
-def err_pragma_loop_invalid_argument_value : Error<
- "%select{invalid value '%0'; must be positive|value '%0' is too large}1">;
def err_pragma_loop_compatibility : Error<
"%select{incompatible|duplicate}0 directives '%1' and '%2'">;
def err_pragma_loop_precedes_nonloop : Error<
diff --git a/clang/include/clang/Basic/FileManager.h b/clang/include/clang/Basic/FileManager.h
index e1f33d57a8980..527bbef24793e 100644
--- a/clang/include/clang/Basic/FileManager.h
+++ b/clang/include/clang/Basic/FileManager.h
@@ -286,12 +286,15 @@ class FileManager : public RefCountedBase<FileManager> {
/// MemoryBuffer if successful, otherwise returning null.
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
getBufferForFile(FileEntryRef Entry, bool isVolatile = false,
- bool RequiresNullTerminator = true);
+ bool RequiresNullTerminator = true,
+ std::optional<int64_t> MaybeLimit = std::nullopt);
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
getBufferForFile(StringRef Filename, bool isVolatile = false,
- bool RequiresNullTerminator = true) const {
- return getBufferForFileImpl(Filename, /*FileSize=*/-1, isVolatile,
- RequiresNullTerminator);
+ bool RequiresNullTerminator = true,
+ std::optional<int64_t> MaybeLimit = std::nullopt) const {
+ return getBufferForFileImpl(Filename,
+ /*FileSize=*/(MaybeLimit ? *MaybeLimit : -1),
+ isVolatile, RequiresNullTerminator);
}
private:
diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td
index 6ca08abdb14f0..c59a17be7808f 100644
--- a/clang/include/clang/Basic/StmtNodes.td
+++ b/clang/include/clang/Basic/StmtNodes.td
@@ -204,6 +204,7 @@ def OpaqueValueExpr : StmtNode<Expr>;
def TypoExpr : StmtNode<Expr>;
def RecoveryExpr : StmtNode<Expr>;
def BuiltinBitCastExpr : StmtNode<ExplicitCastExpr>;
+def EmbedExpr : StmtNode<Expr>;
// Microsoft Extensions.
def MSPropertyRefExpr : StmtNode<Expr>;
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index 9c4b17465e18a..37d570ca5e75b 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -126,6 +126,9 @@ PPKEYWORD(error)
// C99 6.10.6 - Pragma Directive.
PPKEYWORD(pragma)
+// C23 & C++26 #embed
+PPKEYWORD(embed)
+
// GNU Extensions.
PPKEYWORD(import)
PPKEYWORD(include_next)
@@ -999,6 +1002,9 @@ ANNOTATION(header_unit)
// Annotation for end of input in clang-repl.
ANNOTATION(repl_input_end)
+// Annotation for #embed
+ANNOTATION(embed)
+
#undef PRAGMA_ANNOTATION
#undef ANNOTATION
#undef TESTING_KEYWORD
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 15f62c5c1a6ab..0c04d272c1ac7 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -880,6 +880,9 @@ will be ignored}]>;
def L : JoinedOrSeparate<["-"], "L">, Flags<[RenderJoined]>, Group<Link_Group>,
Visibility<[ClangOption, FlangOption]>,
MetaVarName<"<dir>">, HelpText<"Add directory to library search path">;
+def embed_dir_EQ : Joined<["--"], "embed-dir=">, Group<Preprocessor_Group>,
+ Visibility<[ClangOption, CC1Option]>, MetaVarName<"<dir>">,
+ HelpText<"Add directory to embed search path">;
def MD : Flag<["-"], "MD">, Group<M_Group>,
HelpText<"Write a depfile containing user and system headers">;
def MMD : Flag<["-"], "MMD">, Group<M_Group>,
@@ -1473,6 +1476,9 @@ def dD : Flag<["-"], "dD">, Group<d_Group>, Visibility<[ClangOption, CC1Option]>
def dI : Flag<["-"], "dI">, Group<d_Group>, Visibility<[ClangOption, CC1Option]>,
HelpText<"Print include directives in -E mode in addition to normal output">,
MarshallingInfoFlag<PreprocessorOutputOpts<"ShowIncludeDirectives">>;
+def dE : Flag<["-"], "dE">, Group<d_Group>, Visibility<[CC1Option]>,
+ HelpText<"Print embed directives in -E mode in addition to normal output">,
+ MarshallingInfoFlag<PreprocessorOutputOpts<"ShowEmbedDirectives">>;
def dM : Flag<["-"], "dM">, Group<d_Group>, Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>,
HelpText<"Print macro definitions in -E mode instead of normal output">;
def dead__strip : Flag<["-"], "dead_strip">;
diff --git a/clang/include/clang/Frontend/PreprocessorOutputOptions.h b/clang/include/clang/Frontend/PreprocessorOutputOptions.h
index 6e19cae33cf28..654cf22f010f7 100644
--- a/clang/include/clang/Frontend/PreprocessorOutputOptions.h
+++ b/clang/include/clang/Frontend/PreprocessorOutputOptions.h
@@ -32,6 +32,8 @@ class PreprocessorOutputOptions {
LLVM_PREFERRED_TYPE(bool)
unsigned ShowIncludeDirectives : 1; ///< Print includes, imports etc. within preprocessed output.
LLVM_PREFERRED_TYPE(bool)
+ unsigned ShowEmbedDirectives : 1; ///< Print embeds, etc. within preprocessed
+ LLVM_PREFERRED_TYPE(bool)
unsigned RewriteIncludes : 1; ///< Preprocess include directives only.
LLVM_PREFERRED_TYPE(bool)
unsigned RewriteImports : 1; ///< Include contents of transitively-imported modules.
@@ -51,6 +53,7 @@ class PreprocessorOutputOptions {
ShowMacroComments = 0;
ShowMacros = 0;
ShowIncludeDirectives = 0;
+ ShowEmbedDirectives = 0;
RewriteIncludes = 0;
RewriteImports = 0;
MinimizeWhitespace = 0;
diff --git a/clang/include/clang/Lex/PPCallbacks.h b/clang/include/clang/Lex/PPCallbacks.h
index dfc74b52686f1..46cc564086f1c 100644
--- a/clang/include/clang/Lex/PPCallbacks.h
+++ b/clang/include/clang/Lex/PPCallbacks.h
@@ -27,6 +27,7 @@ class IdentifierInfo;
class MacroDefinition;
class MacroDirective;
class MacroArgs;
+struct LexEmbedParametersResult;
/// This interface provides a way to observe the actions of the
/// preprocessor as it does its thing.
@@ -83,6 +84,34 @@ class PPCallbacks {
const Token &FilenameTok,
SrcMgr::CharacteristicKind FileType) {}
+ /// Callback invoked whenever the preprocessor cannot find a file for an
+ /// embed directive.
+ ///
+ /// \param FileName The name of the file being included, as written in the
+ /// source code.
+ ///
+ /// \returns true to indicate that the preprocessor should skip this file
+ /// and not issue any diagnostic.
+ virtual bool EmbedFileNotFound(StringRef FileName) { return false; }
+
+ /// Callback invoked whenever an embed directive has been processed,
+ /// regardless of whether the embed will actually find a file.
+ ///
+ /// \param HashLoc The location of the '#' that starts the embed directive.
+ ///
+ /// \param FileName The name of the file being included, as written in the
+ /// source code.
+ ///
+ /// \param IsAngled Whet...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/95802
More information about the cfe-commits
mailing list