https://github.com/ThePhD created 
https://github.com/llvm/llvm-project/pull/190578

This is a draft pull request containing a mostly-reasonable implementation of 
`#depend` and the builtin `__builtin_std_embed`. It's a draft because the 
proposal has not yet fully passed WG21 and is bouncing back and forth due to 
Committee-internal shenanigans, but this will prevent me from having to 
re-re-reimplement and re-re-rejustify what it would take to make a `consteval` 
builtin embed work.

This pull request will remain a draft until the following is completed:
- [ ] p1040 passes WG21
- [ ] Additional implementation to convert UTF-8/16/32 `char8_t`/`wchar_t` to 
EBCDIC rather than UTF-8 internally (use routines in `llvm/Support` and 
`clang/Basic`)
- [ ] Additional implementations of `std::embed` are added for a fixed 
`N`/`_Limit` template parameter (which require an exact count)
        - [ ] `__builtin_std_embed` with bad arguments
- [ ] Documentation is added for the `__builtin_std_embed`
        - [ ] An entry is added for the c++ status page 
(clang/www/cxx_status.html)
        - [ ] An entry is added in the builtins documentation 
(clang/docs/LanguageExtensions.rst)
        - [ ] Make sure to mention (lack of) support for quirky files such as 
block devices, etc.
- [ ] Tests are added for `__builtin_std_embed`
        - [ ] error reporting with bad arguments
        - [ ] error reporting for too-large numbers on AMD64/ARM64 systems 
(internally limit is `int64_t`, not `uint64_t`, but takes `std::size_t`)
        - [ ] error reporting for bad conversions to UTF-8 internals from 
UTF-16/UTF-32 wide-character strings on appropriate hardware (TODO: figure out 
how "improper" characters that may undergo conversion are handled -- likely 
hard error since replacement with `?` or `U+FFFD` would just result in failures 
(`?` is not allowed) or bad file searches (for `U+FFFD` as UTF-8))
        - [ ] error reporting for missing `#depend`
        - [ ] testing structures with implicit conversions to appropriate 
pointer types
        - [ ] error reporting for structures with implicit conversions to 
inappropriate pointer types
        - [ ] error reporting for appropriate `#depend` but file not found
- [ ] Tests are added for `std::embed`
        - [ ] one billion `static_assert`s, use of `__FILE__`

>From be8d392a5cfb733b98960e08e522e5d1438a84c4 Mon Sep 17 00:00:00 2001
From: ThePhD <[email protected]>
Date: Wed, 1 Apr 2026 19:06:16 +0200
Subject: [PATCH] =?UTF-8?q?[Clang][Lex][Sema]=20=E2=9C=A8=20Full=20std::em?=
 =?UTF-8?q?bed=20and=20#depend=20implementation?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 clang/include/clang/AST/ASTContext.h          |  15 ++
 clang/include/clang/Basic/Builtins.td         |   7 +
 clang/include/clang/Basic/DiagnosticGroups.td |   2 +-
 .../include/clang/Basic/DiagnosticLexKinds.td |   4 +
 .../clang/Basic/InputDependencyCollection.h   |  66 +++++
 clang/include/clang/Basic/ResourceSearch.h    |  37 +++
 clang/include/clang/Basic/TokenKinds.def      |   2 +
 clang/include/clang/Lex/PPCallbacks.h         |  16 ++
 clang/include/clang/Lex/Preprocessor.h        |   9 +-
 clang/include/clang/Sema/Sema.h               |   1 +
 clang/lib/AST/ASTContext.cpp                  |  12 +
 clang/lib/AST/ExprConstant.cpp                | 234 +++++++++++++++++-
 clang/lib/Basic/CMakeLists.txt                |   2 +
 clang/lib/Basic/IdentifierTable.cpp           |   1 +
 clang/lib/Basic/InputDependencyCollection.cpp | 181 ++++++++++++++
 clang/lib/Basic/ResourceSearch.cpp            | 107 ++++++++
 clang/lib/Frontend/ASTUnit.cpp                |   8 +-
 clang/lib/Frontend/CompilerInstance.cpp       |   2 +
 clang/lib/Frontend/DependencyFile.cpp         |  91 ++++++-
 clang/lib/Lex/PPDirectives.cpp                | 128 +++++-----
 clang/lib/Lex/Preprocessor.cpp                |  22 +-
 clang/lib/Sema/SemaChecking.cpp               | 151 +++++++++++
 .../clang-import-test/clang-import-test.cpp   |   2 +
 clang/unittests/Lex/PPCallbacksTest.cpp       |   1 +
 libcxx/include/CMakeLists.txt                 |   1 +
 libcxx/include/embed                          | 113 +++++++++
 libcxx/include/version                        |   7 +
 27 files changed, 1135 insertions(+), 87 deletions(-)
 create mode 100644 clang/include/clang/Basic/InputDependencyCollection.h
 create mode 100644 clang/include/clang/Basic/ResourceSearch.h
 create mode 100644 clang/lib/Basic/InputDependencyCollection.cpp
 create mode 100644 clang/lib/Basic/ResourceSearch.cpp
 create mode 100644 libcxx/include/embed

diff --git a/clang/include/clang/AST/ASTContext.h 
b/clang/include/clang/AST/ASTContext.h
index ba1b58489c327..56cf139cad791 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -28,6 +28,7 @@
 #include "clang/AST/Type.h"
 #include "clang/AST/TypeOrdering.h"
 #include "clang/Basic/LLVM.h"
+#include "clang/Basic/InputDependencyCollection.h"
 #include "clang/Basic/PartialDiagnostic.h"
 #include "clang/Basic/SourceLocation.h"
 #include "llvm/ADT/DenseMap.h"
@@ -131,6 +132,7 @@ class OMPTraitInfo;
 class ParentMapContext;
 struct ParsedTargetAttr;
 class Preprocessor;
+class PreprocessorOptions;
 class ProfileList;
 class StoredDeclsMap;
 class TargetAttr;
@@ -567,6 +569,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
   // A mapping from Scalable Vector Type keys to their corresponding QualType.
   mutable llvm::DenseMap<llvm::ScalableVecTyKey, QualType> ScalableVecTyMap;
 
+  // Same preprocessor options from other lexers, so we can look up
+  // embedded files
+  PreprocessorOptions const *PPOpts = nullptr;
+
+
   ASTContext &this_() { return *this; }
 
 public:
@@ -802,6 +809,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
   mutable DeclarationNameTable DeclarationNames;
   IntrusiveRefCntPtr<ExternalASTSource> ExternalSource;
   ASTMutationListener *Listener = nullptr;
+  std::shared_ptr<InputDependencyCollection> InputDependencyPatterns = 
std::make_shared<InputDependencyCollection>();
 
   /// Returns the clang bytecode interpreter context.
   interp::Context &getInterpContext() const;
@@ -1396,6 +1404,13 @@ class ASTContext : public RefCountedBase<ASTContext> {
   ASTContext &operator=(const ASTContext &) = delete;
   ~ASTContext();
 
+  /// Set the preprocessor options to use right now
+  void setCurrentPreprocessorOptions(PreprocessorOptions const *NewPPOpts);
+  void setCurrentPreprocessorOptions(const PreprocessorOptions &NewPPOpts);
+
+  /// Get the preprocessor options we are using. Can be null!
+  PreprocessorOptions const* getCurrentPreprocessorOptions() const;
+
   /// Attach an external AST source to the AST context.
   ///
   /// The external AST source provides the ability to load parts of
diff --git a/clang/include/clang/Basic/Builtins.td 
b/clang/include/clang/Basic/Builtins.td
index b8bbc544595e2..d33dc0fe32233 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -1006,6 +1006,13 @@ def GetVtablePointer : LangBuiltin<"CXX_LANG"> {
   let Prototype = "void*(void*)";
 }
 
+// p1040 std::embed
+def StdEmbed : Builtin {
+  let Spellings = ["__builtin_std_embed"];
+  let Attributes = [NoThrow, Const, Consteval];
+  let Prototype = "void const*(size_t&, ...)";
+}
+
 // GCC exception builtins
 def EHReturn : Builtin {
   let Spellings = ["__builtin_eh_return"];
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td 
b/clang/include/clang/Basic/DiagnosticGroups.td
index dc7280c66ea79..de7e782ef6174 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -1520,7 +1520,7 @@ def : DiagGroup<"c++1y-extensions", [CXX14]>;
 def : DiagGroup<"c++1z-extensions", [CXX17]>;
 def : DiagGroup<"c++2a-extensions", [CXX20]>;
 def : DiagGroup<"c++2b-extensions", [CXX23]>;
-def : DiagGroup<"c++2c-extensions", [CXX26]>;
+def CXX2C : DiagGroup<"c++2c-extensions", [CXX26]>;
 
 def DelegatingCtorCycles :
   DiagGroup<"delegating-ctor-cycles">;
diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td 
b/clang/include/clang/Basic/DiagnosticLexKinds.td
index bea0aafac98cf..433379d680857 100644
--- a/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -464,6 +464,9 @@ def warn_c23_compat_warning_directive : Warning<
 def ext_pp_embed_directive : ExtWarn<
   "#embed is a %select{C23|Clang}0 extension">,
   InGroup<C23>;
+def ext_pp_depend_directive : ExtWarn<
+  "#depend is a %select{C++2c|Clang}0 extension">,
+  InGroup<CXX2C>, DefaultIgnore;
 def warn_compat_pp_embed_directive : Warning<
   "#embed is incompatible with C standards before C23">,
   InGroup<CPre23Compat>, DefaultIgnore;
@@ -579,6 +582,7 @@ def err_pp_including_mainfile_in_preamble : Error<
 def err_pp_empty_filename : Error<"empty filename">;
 def err_pp_include_too_deep : Error<"#include nested too deeply">;
 def err_pp_expects_filename : Error<"expected \"FILENAME\" or <FILENAME>">;
+def err_pp_expects_pattern : Error<"expected \"PATTERN\" or <PATTERN>">;
 def err_pp_macro_not_identifier : Error<"macro name must be an identifier">;
 def err_pp_missing_macro_name : Error<"macro name missing">;
 def err_pp_missing_rparen_in_macro_def : Error<
diff --git a/clang/include/clang/Basic/InputDependencyCollection.h 
b/clang/include/clang/Basic/InputDependencyCollection.h
new file mode 100644
index 0000000000000..d29a9e4192f37
--- /dev/null
+++ b/clang/include/clang/Basic/InputDependencyCollection.h
@@ -0,0 +1,66 @@
+//===--- InputDependencyCollection.h - Searching for Resources --*- C++ 
-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// User-provided filters include/exclude profile instrumentation in certain
+// functions.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_BASIC_INPUTDEPENDENCYCOLLECTION_H
+#define LLVM_CLANG_BASIC_INPUTDEPENDENCYCOLLECTION_H
+
+#include "clang/Basic/FileEntry.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/Regex.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+
+class FileManager;
+
+/// How to handle various forms of input dependency root patterns for search
+/// purposes.
+enum class RootPatternScanType {
+  None = 0b00,
+  Directory = 0b01,
+  RecursiveDirectory = 0b10,
+  DirectoryAndRecursiveDirectory = 0b11
+};
+
+struct PatternFilter {
+  std::string Input;
+  std::string SearchRoot;
+  std::string PatternRoot;
+  std::string Pattern;
+  llvm::Regex PatternRegex;
+  RootPatternScanType RootHandling;
+  bool Exported;
+
+  PatternFilter(std::string Input);
+
+  bool Check(StringRef Filename) const;
+};
+
+class InputDependencyCollection {
+private:
+  std::vector<PatternFilter> PatternFilters;
+
+  static PatternFilter ComputeFilter(std::string Pattern, bool Exported);
+
+public:
+  InputDependencyCollection() = default;
+
+  PatternFilter &Add(std::string Pattern, bool IsAngled, bool Exported,
+                     FileManager &FM,
+                     const std::vector<std::string> &SearchEntries,
+                     OptionalFileEntryRef LookupFrom);
+  bool Check(llvm::StringRef Filename) const;
+};
+} // namespace clang
+
+#endif
diff --git a/clang/include/clang/Basic/ResourceSearch.h 
b/clang/include/clang/Basic/ResourceSearch.h
new file mode 100644
index 0000000000000..da163b9698841
--- /dev/null
+++ b/clang/include/clang/Basic/ResourceSearch.h
@@ -0,0 +1,37 @@
+//===--- ResourceSearch.h - Searching for Resources -------------*- C++ 
-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// User-provided filters include/exclude profile instrumentation in certain
+// functions.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_BASIC_RESOURCESEARCH_H
+#define LLVM_CLANG_BASIC_RESOURCESEARCH_H
+
+#include "clang/Basic/FileEntry.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include <memory>
+#include <optional>
+
+namespace clang {
+
+class FileManager;
+
+OptionalFileEntryRef
+LookupFileWithStdVec(StringRef Filename, bool isAngled, bool OpenFile,
+                     FileManager &FM,
+                     const std::vector<std::string> &SearchEntries,
+                     OptionalFileEntryRef LookupFromFile);
+OptionalFileEntryRef LookupFileWith(StringRef Filename, bool isAngled,
+                                    bool OpenFile, FileManager &FM,
+                                    ArrayRef<StringRef> SearchEntries,
+                                    OptionalFileEntryRef LookupFromFile);
+} // namespace clang
+
+#endif
diff --git a/clang/include/clang/Basic/TokenKinds.def 
b/clang/include/clang/Basic/TokenKinds.def
index 8b9f613037718..28f706ce87f70 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -132,6 +132,8 @@ PPKEYWORD(pragma)
 
 // C23 & C++26 #embed
 PPKEYWORD(embed)
+// C++29 #depend
+PPKEYWORD(depend)
 
 // C++20 Module Directive
 PPKEYWORD(module)
diff --git a/clang/include/clang/Lex/PPCallbacks.h 
b/clang/include/clang/Lex/PPCallbacks.h
index 51c6a31e143b8..fbe31e7cf649b 100644
--- a/clang/include/clang/Lex/PPCallbacks.h
+++ b/clang/include/clang/Lex/PPCallbacks.h
@@ -29,6 +29,7 @@ class MacroDefinition;
 class MacroDirective;
 class MacroArgs;
 struct LexEmbedParametersResult;
+struct PatternFilter;
 
 /// This interface provides a way to observe the actions of the
 /// preprocessor as it does its thing.
@@ -175,6 +176,12 @@ class PPCallbacks {
                                   bool ModuleImported,
                                   SrcMgr::CharacteristicKind FileType) {}
 
+  /// Hook called when a 'depend' directive is read.
+  virtual void DependDirective(SourceLocation HashLoc, const Token &DependTok,
+                               StringRef FileName, bool IsAngled,
+                               const PatternFilter& Filter,
+                               OptionalFileEntryRef CurrentFile) {}
+
   /// Callback invoked whenever a submodule was entered.
   ///
   /// \param M The submodule we have entered.
@@ -543,6 +550,15 @@ class PPChainedCallbacks : public PPCallbacks {
                                SuggestedModule, ModuleImported, FileType);
   }
 
+  /// Hook called whenever an \#depend is seen.
+  void DependDirective(SourceLocation HashLoc, const Token &DependTok,
+                               StringRef Pattern, bool IsAngled,
+                               const PatternFilter& Filter,
+                               OptionalFileEntryRef CurrentFile) override {
+    First->DependDirective(HashLoc, DependTok, Pattern, IsAngled, Filter, 
CurrentFile);
+    Second->DependDirective(HashLoc, DependTok, Pattern, IsAngled, Filter, 
CurrentFile);
+  }
+
   void EnteredSubmodule(Module *M, SourceLocation ImportLoc,
                         bool ForPragma) override {
     First->EnteredSubmodule(M, ImportLoc, ForPragma);
diff --git a/clang/include/clang/Lex/Preprocessor.h 
b/clang/include/clang/Lex/Preprocessor.h
index c7e152a75f51f..33e0984cd7d80 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -17,6 +17,7 @@
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/DiagnosticIDs.h"
 #include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/InputDependencyCollection.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/LangOptions.h"
 #include "clang/Basic/Module.h"
@@ -343,6 +344,9 @@ class Preprocessor {
   /// The kind of translation unit we are processing.
   const TranslationUnitKind TUKind;
 
+  /// The #depend dependency patterns seen in this translation unit
+  std::shared_ptr<InputDependencyCollection> InputDependencyPatterns = 
std::make_shared<InputDependencyCollection>();
+
   /// Returns a pointer into the given file's buffer that's guaranteed
   /// to be between tokens. The returned pointer is always before \p Start.
   /// The maximum distance betweenthe returned pointer and \p Start is
@@ -1812,7 +1816,8 @@ class Preprocessor {
   void LexTokensUntilEOF(std::vector<Token> *Tokens = nullptr);
 
   /// Lex a token, forming a header-name token if possible.
-  bool LexHeaderName(Token &Result, bool AllowMacroExpansion = true);
+  bool LexHeaderName(Token &Result, bool AllowMacroExpansion = true,
+                     bool SkipFirst = false);
 
   /// Lex the parameters for an #embed directive, returns nullopt on error.
   std::optional<LexEmbedParametersResult> LexEmbedParameters(Token &Current,
@@ -2895,6 +2900,8 @@ class Preprocessor {
       const FileEntry *LookupFromFile, StringRef &LookupFilename,
       SmallVectorImpl<char> &RelativePath, SmallVectorImpl<char> &SearchPath,
       ModuleMap::KnownHeader &SuggestedModule, bool isAngled);
+  // Input dependency caching
+  void HandleDependDirective(SourceLocation HashLoc, Token &Tok);
   // Binary data inclusion
   void HandleEmbedDirective(SourceLocation HashLoc, Token &Tok);
   void HandleEmbedDirectiveImpl(SourceLocation HashLoc,
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 1b8a9803be472..a4ad6b01b52ae 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -3053,6 +3053,7 @@ class Sema final : public SemaBase {
   bool CheckInvalidBuiltinCountedByRef(const Expr *E,
                                        BuiltinCountedByRefKind K);
   bool BuiltinCountedByRef(CallExpr *TheCall);
+  bool BuiltinStdEmbed(CallExpr *TheCall);
 
   // Matrix builtin handling.
   ExprResult BuiltinMatrixTranspose(CallExpr *TheCall, ExprResult CallResult);
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index ee7f823b014b2..d0cde5397663b 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -903,6 +903,18 @@ ASTContext::ASTContext(LangOptions &LOpts, SourceManager 
&SM,
   addTranslationUnitDecl();
 }
 
+void ASTContext::setCurrentPreprocessorOptions(const PreprocessorOptions 
&NewOpts) {
+  PPOpts = &NewOpts;
+}
+
+void ASTContext::setCurrentPreprocessorOptions(PreprocessorOptions const 
*NewOpts) {
+  PPOpts = NewOpts;
+}
+
+PreprocessorOptions const *ASTContext::getCurrentPreprocessorOptions() const {
+  return PPOpts;
+}
+
 void ASTContext::cleanup() {
   // Release the DenseMaps associated with DeclContext objects.
   // FIXME: Is this the ideal solution?
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 4f45fa728c605..084fe16bf04f2 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -53,13 +53,18 @@
 #include "clang/AST/TypeLoc.h"
 #include "clang/Basic/Builtins.h"
 #include "clang/Basic/DiagnosticSema.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/ResourceSearch.h"
+#include "clang/Basic/SourceManager.h"
 #include "clang/Basic/TargetBuiltins.h"
 #include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/PreprocessorOptions.h"
 #include "llvm/ADT/APFixedPoint.h"
 #include "llvm/ADT/Sequence.h"
 #include "llvm/ADT/SmallBitVector.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/Casting.h"
+#include "llvm/Support/ConvertUTF.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/SaveAndRestore.h"
 #include "llvm/Support/SipHash.h"
@@ -3544,13 +3549,16 @@ static APSInt extractStringLiteralCharacter(EvalInfo 
&Info, const Expr *Lit,
   if (auto PE = dyn_cast<PredefinedExpr>(Lit))
     Lit = PE->getFunctionName();
   const StringLiteral *S = cast<StringLiteral>(Lit);
+  const StringLiteralKind SLK = S->getKind();
   const ConstantArrayType *CAT =
       Info.Ctx.getAsConstantArrayType(S->getType());
   assert(CAT && "string literal isn't an array");
   QualType CharType = CAT->getElementType();
-  assert(CharType->isIntegerType() && "unexpected character type");
+  assert(((SLK == StringLiteralKind::Binary && 
CharType->isIntegralOrEnumerationType())
+      || (SLK != StringLiteralKind::Binary && CharType->isIntegerType()))
+    && "unexpected character type");
   APSInt Value(Info.Ctx.getTypeSize(CharType),
-               CharType->isUnsignedIntegerType());
+               CharType->isUnsignedIntegerOrEnumerationType());
   if (Index < S->getLength())
     Value = S->getCodeUnit(Index);
   return Value;
@@ -10688,7 +10696,223 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const 
CallExpr *E,
         return false;
     }
   }
+  case Builtin::BI__builtin_std_embed: {
+    const Expr *SizeOutArg = E->getArg(0);
+    const Expr *PtrSpecifierArg = E->getArg(1);
+    const Expr *ResourceNameSizeArg = E->getArg(2);
+    const Expr *ResourceNamePtrArg = E->getArg(3);
+    const Expr *OffsetArg = E->getArg(4);
+    const Expr *LimitArg = E->getNumArgs() == 6 ? E->getArg(5) : nullptr;
+
+    QualType ArrElementTy = PtrSpecifierArg->getType()->getPointeeType();
+
+    LValue ResourceNamePtrLVal;
+    if (!evaluatePointer(ResourceNamePtrArg, ResourceNamePtrLVal)) {
+      return Error(ResourceNamePtrArg);
+    }
+
+    APSInt ResourceNameSizeVal;
+    if (!EvaluateInteger(ResourceNameSizeArg, ResourceNameSizeVal, Info)) {
+      return Error(ResourceNameSizeArg);
+    }
+    if (ResourceNameSizeVal.getBitWidth() > 64) {
+      Info.FFDiag(ResourceNameSizeArg->getBeginLoc(), diag::err_ice_too_large) 
<< OffsetArg << 64 << 1;
+      return false;
+    }
+    APValue ResourceNamePtrVal;
+    ResourceNamePtrLVal.moveInto(ResourceNamePtrVal);
+    uint64_t ResourceNameSize = ResourceNameSizeVal.getZExtValue();
+
+    std::string ResourceName;
+    const QualType SizeTy = Info.Ctx.getSizeType();
+    const QualType WCharTy = Info.Ctx.getWideCharType();
+    const size_t SizeTySize = Info.Ctx.getTypeSize(SizeTy);
+    const size_t WCharTySize = Info.Ctx.getTypeSize(WCharTy);
+    const QualType 
ResourceNameCharTy(ResourceNamePtrArg->getType()->getPointeeOrArrayElementType(),
 0);
+    if (ResourceNameCharTy->isChar8Type() || ResourceNameCharTy->isCharType() 
|| (ResourceNameCharTy->isWideCharType() && WCharTySize == 8)) {
+      // Assume the ResourceName is directly usable as an 8-bit transmuation
+      for (size_t Index = 0; Index < ResourceNameSize; ++Index) {
+        APValue Char;
+        if (!handleLValueToRValueConversion(Info, ResourceNamePtrArg,
+              ResourceNameCharTy, ResourceNamePtrLVal, Char)) {
+          return Error(ResourceNamePtrArg);
+        }
+        ResourceName.push_back(static_cast<char>(static_cast<unsigned 
char>(Char.getInt().getExtValue())));
+        
+        if (!HandleLValueArrayAdjustment(Info, ResourceNamePtrArg,
+            ResourceNamePtrLVal, ResourceNameCharTy, 1)) {
+          return Error(ResourceNamePtrArg);
+        }
+      }
+    }
+    else if (ResourceNameCharTy->isWideCharType()) {
+      // we assume either UTF-16, or UTF-32 based on the size of the string
+      // transmute accordingly
+      if (WCharTySize == 16) {
+        llvm::SmallVector<llvm::UTF16, 64> ResourceNameU16;
+        for (size_t Index = 0; Index < ResourceNameSize; ++Index) {
+          APValue Char;
+          if (!handleLValueToRValueConversion(Info, ResourceNamePtrArg,
+                ResourceNameCharTy, ResourceNamePtrLVal, Char)) {
+            return Error(ResourceNamePtrArg);
+          }
+          
ResourceName.push_back(static_cast<llvm::UTF16>(Char.getInt().getExtValue()));
+          
+          if (!HandleLValueArrayAdjustment(Info, ResourceNamePtrArg,
+              ResourceNamePtrLVal, ResourceNameCharTy, 1)) {
+            return Error(ResourceNamePtrArg);
+          }
+        }
+        if (!llvm::convertUTF16ToUTF8String(ResourceNameU16, ResourceName)){
+          // error: bad name conversion
+          return Error(ResourceNamePtrArg);
+        }
+      }
+      else if (WCharTySize == 32) {
+        llvm::SmallVector<llvm::UTF32, 64> ResourceNameU32;
+        for (size_t Index = 0; Index < ResourceNameSize; ++Index) {
+          APValue Char;
+          if (!handleLValueToRValueConversion(Info, ResourceNamePtrArg,
+                ResourceNameCharTy, ResourceNamePtrLVal, Char)) {
+            return false;
+          }
+          
ResourceName.push_back(static_cast<llvm::UTF32>(Char.getInt().getExtValue()));
+          
+          if (!HandleLValueArrayAdjustment(Info, ResourceNamePtrArg,
+              ResourceNamePtrLVal, ResourceNameCharTy, 1)) {
+                return false;
+          }
+        }
+        if (!llvm::convertUTF32ToUTF8String(ResourceNameU32, ResourceName)) {
+          // error: bad name conversion
+          return Error(ResourceNamePtrArg);
+        }
+      }
+      else {
+        llvm::report_fatal_error("The filename has a wide character type that 
cannot be converted to a UTF-8/multibyte string");
+      }
+    }
+    else {
+      llvm::report_fatal_error("The filename has an unusuable or 
unrecognizable character type");
+    }
+
+    uint64_t DataSize = 0;
+    uint64_t DataOffset = 0;
+    std::optional<int64_t> MaybeLimit = std::nullopt;
+    
+    APSInt OffsetVal;
+    if (!EvaluateInteger(OffsetArg, OffsetVal, Info)) {
+      return Error(OffsetArg);
+    }
+    if (OffsetVal.getBitWidth() > 64) {
+      Info.FFDiag(OffsetArg->getBeginLoc(), diag::err_ice_too_large) << 
OffsetArg << 64 << 0;
+      return false;
+    }
+    DataOffset = OffsetVal.getZExtValue();
 
+    if (LimitArg) {
+      APSInt LimitVal;
+      if (!EvaluateInteger(LimitArg, LimitVal, Info)) {
+        return Error(OffsetArg);
+      }
+      if (LimitVal.getBitWidth() > 64) {
+        Info.FFDiag(LimitArg->getBeginLoc(), diag::err_ice_too_large) << 
LimitArg << 64 << 0;
+        return false;
+      }
+      uint64_t FullLimit = LimitVal.getZExtValue();
+      if (FullLimit > 
static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) {
+        // error: implementation limit here since we can only
+        // have a 63-bit unsigned number, not a 64-bit one
+        Info.FFDiag(LimitArg->getBeginLoc(), diag::err_ice_too_large) << 
FullLimit << 64 << 0;
+        return false;
+      }
+      MaybeLimit = static_cast<int64_t>(FullLimit);
+    }
+
+    SourceManager &SM = Info.Ctx.getSourceManager();
+    FileManager &FM = SM.getFileManager();
+    PreprocessorOptions const* MaybePPOpts = 
Info.Ctx.getCurrentPreprocessorOptions();
+    const std::vector<std::string>* MaybeSearchEntries = nullptr;
+    const std::vector<std::string> EmptySearchEntries(0);
+    FileID ThisFileID = SM.getFileID(Info.CurrentCall->CallRange.getBegin());
+    OptionalFileEntryRef ThisFile = std::nullopt;
+    if (ThisFileID.isValid()) {
+      ThisFile = SM.getFileEntryRefForID(ThisFileID);
+    }
+    if (MaybePPOpts) {
+      MaybeSearchEntries = &MaybePPOpts->EmbedEntries;
+    }
+    else {
+      MaybeSearchEntries = &EmptySearchEntries;
+    }
+    OptionalFileEntryRef ResourceFile =
+      LookupFileWithStdVec(ResourceName, false, true, FM, *MaybeSearchEntries, 
ThisFile);
+    if (!ResourceFile) {
+      Info.FFDiag(ResourceNamePtrArg->getBeginLoc(), 
diag::err_cannot_open_file) << ResourceName << "cannot find a matching resource 
to open";
+      return false;
+    }
+    if (Info.Ctx.InputDependencyPatterns) {
+      StringRef ResourceSearchName = 
ResourceFile->getFileEntry().tryGetRealPathName();
+      if (ResourceSearchName.empty()) {
+        ResourceSearchName = ResourceName;
+      }
+      if (!Info.Ctx.InputDependencyPatterns->Check(ResourceSearchName)) {
+        Info.FFDiag(ResourceNamePtrArg->getBeginLoc(), 
diag::err_cannot_open_file) << ResourceName << "no '#depend' directive matches 
the found resource";
+        return false;
+      }
+    }
+    llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MaybeBinaryData =
+      FM.getBufferForFile(*ResourceFile, true, false, MaybeLimit, false);
+    if (auto Err = MaybeBinaryData.getError()) {
+      std::string ExtraMessage = Err.message();
+      std::string ErrorMessage = "could not open the resource";
+      if (!ExtraMessage.empty()) {
+        ErrorMessage += ", ";
+        ErrorMessage += ExtraMessage;
+      }
+      Info.FFDiag(ResourceNamePtrArg->getBeginLoc(), 
diag::err_cannot_open_file) << ResourceName << ErrorMessage;
+      return false;
+    }
+    llvm::MemoryBuffer *BinaryData = MaybeBinaryData->get();
+    if (!BinaryData) {
+      Info.FFDiag(ResourceNamePtrArg->getBeginLoc(), 
diag::err_cannot_open_file) << ResourceName << "found the resource but unable 
to read the binary data";
+      return false;
+    }
+    size_t FullDataSize = BinaryData->getBufferSize();
+    DataSize = std::max<size_t>(0, std::min<size_t>(
+      DataOffset > FullDataSize
+      ? 0 : FullDataSize - DataOffset,
+      MaybeLimit ? *MaybeLimit : std::numeric_limits<size_t>::max()));
+
+    // Write out size
+    LValue SizeOutLVal;
+    if (!EvaluateLValue(SizeOutArg, SizeOutLVal, Info)) {
+      return Error(SizeOutArg);
+    }
+    APSInt BackingArraySizeVal(llvm::APInt(SizeTySize, DataSize, false), true);
+    APValue SizeOutResult(BackingArraySizeVal);
+    if (!handleAssignment(Info, SizeOutArg, SizeOutLVal, 
SizeOutArg->getType(), SizeOutResult)) {
+      return Error(SizeOutArg);
+    }
+
+    // return data literal pointer to string
+    SourceLocation BuiltinLoc = E->getBeginLoc();
+    // TODO: perhaps there may be smarter ways to load this data up;
+    // right now, this is not doing too much on the face with caching or smart
+    // deduplication in the compiler.
+    StringRef TargetData(BinaryData->getBufferStart() + DataOffset, DataSize);
+    QualType BackingArrayTy = Info.Ctx.getConstantArrayType(
+        ArrElementTy, BackingArraySizeVal, nullptr, ArraySizeModifier::Normal, 
0);
+    const ConstantArrayType *BackingArrayConstantArrayTy = 
cast<ConstantArrayType>(BackingArrayTy);
+    StringLiteral *DataLiteral = StringLiteral::Create(Info.Ctx, TargetData,
+      StringLiteralKind::Binary, false, BackingArrayTy, 
ArrayRef<SourceLocation>(&BuiltinLoc, 1));
+    if (!EvaluateLValue(DataLiteral, Result, Info)) {
+      return Error(E);
+    }
+    // inform the result we have put a string literal in there
+    Result.addArray(Info, E, BackingArrayConstantArrayTy); 
+    return true;
+  }
   default:
     return false;
   }
@@ -15284,8 +15508,10 @@ class IntExprEvaluator
   bool Success(const llvm::APSInt &SI, const Expr *E, APValue &Result) {
     assert(E->getType()->isIntegralOrEnumerationType() &&
            "Invalid evaluation result.");
-    assert(SI.isSigned() == E->getType()->isSignedIntegerOrEnumerationType() &&
-           "Invalid evaluation result.");
+    auto Ty = E->getType();
+    if (SI.isSigned() != Ty->isSignedIntegerOrEnumerationType()) {
+      assert(false && "Invalid evaluation result.");
+    }
     assert(SI.getBitWidth() == Info.Ctx.getIntWidth(E->getType()) &&
            "Invalid evaluation result.");
     Result = APValue(SI);
diff --git a/clang/lib/Basic/CMakeLists.txt b/clang/lib/Basic/CMakeLists.txt
index adfc6ee326b5a..936e2798e65d7 100644
--- a/clang/lib/Basic/CMakeLists.txt
+++ b/clang/lib/Basic/CMakeLists.txt
@@ -71,6 +71,7 @@ add_clang_library(clangBasic
   FileManager.cpp
   FileSystemStatCache.cpp
   IdentifierTable.cpp
+  InputDependencyCollection.cpp
   LangOptions.cpp
   LangStandards.cpp
   MakeSupport.cpp
@@ -83,6 +84,7 @@ add_clang_library(clangBasic
   ParsedAttrInfo.cpp
   ProfileList.cpp
   NoSanitizeList.cpp
+  ResourceSearch.cpp
   SanitizerSpecialCaseList.cpp
   Sanitizers.cpp
   Sarif.cpp
diff --git a/clang/lib/Basic/IdentifierTable.cpp 
b/clang/lib/Basic/IdentifierTable.cpp
index 7f96777fbd4cb..aa1a4cac6ec17 100644
--- a/clang/lib/Basic/IdentifierTable.cpp
+++ b/clang/lib/Basic/IdentifierTable.cpp
@@ -439,6 +439,7 @@ tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const {
 
   CASE( 6, 'a', 's', assert);
   CASE( 6, 'd', 'f', define);
+  CASE( 6, 'd', 'p', depend);
   CASE( 6, 'i', 'n', ifndef);
   CASE( 6, 'i', 'p', import);
   CASE( 6, 'm', 'd', module);
diff --git a/clang/lib/Basic/InputDependencyCollection.cpp 
b/clang/lib/Basic/InputDependencyCollection.cpp
new file mode 100644
index 0000000000000..844b3694b10f5
--- /dev/null
+++ b/clang/lib/Basic/InputDependencyCollection.cpp
@@ -0,0 +1,181 @@
+//===--- InputDependencyCollection.h - Searching for Resource----*- C++ 
-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// User-provided filters include/exclude profile instrumentation in certain
+// functions or files.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/InputDependencyCollection.h"
+#include "clang/Basic/FileManager.h"
+#include "llvm/Support/Path.h"
+#include <filesystem>
+
+using namespace llvm;
+
+namespace clang {
+
+PatternFilter::PatternFilter(std::string Pattern)
+    : Input(std::move(Pattern)), SearchRoot(""), PatternRoot(""), Pattern(""),
+      RootHandling(RootPatternScanType::None), Exported(false) {}
+
+bool PatternFilter::Check(StringRef Filename) const {
+  if (!PatternRoot.empty()) {
+    // if the pattern root is not empty, first check if the filename is 
anchored
+    // in the pattern's root exit early if it's not
+    if (!Filename.contains(PatternRoot)) {
+      return false;
+    }
+  }
+  // otherwise, commit to doing a regex search
+  if (PatternRegex.match(Filename)) {
+    // it matches, we can find it
+    return true;
+  }
+  return false;
+}
+
+PatternFilter InputDependencyCollection::ComputeFilter(std::string Pattern,
+                                                       bool Exported) {
+  static constexpr const char *RecursiveReplacement = ".*";
+  static constexpr const std::size_t RecursiveReplacementSize = 2;
+  static constexpr const char *Replacement = "[^/\\]*";
+  static constexpr const std::size_t ReplacementSize = 6;
+  PatternFilter Computed(std::move(Pattern));
+  // Technically, this is a very conservative estimate, since this is only in
+  // the most harmless of cases.
+  Computed.Pattern.reserve(Computed.Input.size());
+  const std::size_t InputSize = Computed.Input.size();
+  std::optional<std::size_t> LastRootSeparator = std::nullopt;
+  std::optional<std::size_t> LastStar = std::nullopt;
+  std::optional<std::size_t> LastStarStar = std::nullopt;
+  for (std::size_t I = 0; I < InputSize; ++I) {
+    const char CharVal = Computed.Input[I];
+    switch (CharVal) {
+    case '*':
+      if (I < InputSize && Computed.Input[I + 1] == '*') {
+        // completely unrestricted: replace with `.*`
+        ++I;
+        Computed.RootHandling = static_cast<RootPatternScanType>(
+            static_cast<unsigned int>(RootPatternScanType::RecursiveDirectory) 
|
+            static_cast<unsigned int>(Computed.RootHandling));
+        Computed.Pattern.append(RecursiveReplacement, 
RecursiveReplacementSize);
+        LastStarStar = I;
+      } else {
+        // regular non-path-delimited changers: `[^\\/]*
+        Computed.RootHandling = static_cast<RootPatternScanType>(
+            static_cast<unsigned int>(
+                LastStar
+                    ? (*LastStar < LastRootSeparator
+                           ? 
RootPatternScanType::DirectoryAndRecursiveDirectory
+                           : RootPatternScanType::Directory)
+                    : RootPatternScanType::Directory) |
+            static_cast<unsigned int>(Computed.RootHandling));
+        Computed.Pattern.append(Replacement, ReplacementSize);
+        LastStar = I;
+      }
+      break;
+    case ')':
+    case '(':
+    case '[':
+    case ']':
+    case '{':
+    case '}':
+    case '^':
+    case '$':
+    case '.':
+    case '+':
+    case '?':
+    case '|':
+      // cases where the character must be escaped
+      Computed.Pattern.push_back('\\');
+      Computed.Pattern.push_back(CharVal);
+      break;
+    case '/':
+      if (Computed.RootHandling == RootPatternScanType::None)
+        LastRootSeparator = I;
+      Computed.Pattern.append("[/\\]", 4);
+      break;
+    case '\\':
+      if (Computed.RootHandling == RootPatternScanType::None)
+        LastRootSeparator = I;
+      Computed.Pattern.append("[/\\]", 4);
+      break;
+    default:
+      Computed.Pattern.push_back(CharVal);
+      break;
+    }
+  }
+  Computed.Pattern.push_back('$');
+  Computed.PatternRoot.append(
+      Computed.Input.cbegin(),
+      Computed.Input.cbegin() +
+          LastRootSeparator.value_or(static_cast<std::size_t>(0)));
+  // If LastSeperator == 0 and the Input's size is Non-Zero Could be a 
directory
+  // OR a file we're relying on... could be a bit strange to work with!
+  // nevertheless, we'll treat it as a file, no reason to use `stat` and other
+  // temporary checks to try and determine whether or not something is a file
+  // versus a directory here.
+  Computed.PatternRegex = Regex(Computed.Pattern, Regex::NoFlags);
+  return Computed;
+}
+
+PatternFilter &
+InputDependencyCollection::Add(std::string Pattern, bool IsAngled,
+                               bool Exported, FileManager &FM,
+                               const std::vector<std::string> &SearchEntries,
+                               OptionalFileEntryRef LookupFrom) {
+  PatternFilters.push_back(ComputeFilter(std::move(Pattern), Exported));
+  PatternFilter &Filter = PatternFilters.back();
+  if (Filter.PatternRoot.empty() ||
+      llvm::sys::path::is_absolute(Filter.PatternRoot)) {
+    // nothing else to do since it's absolute
+    // or the PatternRoot is empty, so we can't do any
+    // pre-culling.
+    return Filter;
+  }
+  // Find a plausible search root among the entries, if possible, to anchor 
this
+  // to a given entry
+  auto TryDetermineSearchRoot = [&](StringRef SearchEntry) -> bool {
+    if (SearchEntry.contains(Filter.PatternRoot)) {
+      // the entry is contained within: approve the search entry as the search
+      // root
+      Filter.SearchRoot.assign(SearchEntry.begin(), SearchEntry.end());
+      return true;
+    }
+    return false;
+  };
+  if (!IsAngled && LookupFrom) {
+    // quote search; including the optional file entry as a root search 
location
+    // too
+    StringRef LookupDirName = LookupFrom->getDir().getName();
+    if (TryDetermineSearchRoot(LookupDirName)) {
+      return Filter;
+    }
+  }
+  for (StringRef SearchEntry : SearchEntries) {
+    if (TryDetermineSearchRoot(SearchEntry)) {
+      return Filter;
+    }
+  }
+  // if we're here, then we just need to make the SearchRoot identical to the
+  // Pattern's root.
+  Filter.SearchRoot = Filter.PatternRoot;
+  return Filter;
+}
+
+bool InputDependencyCollection::Check(StringRef Filename) const {
+  for (const auto &Filter : PatternFilters) {
+    if (Filter.Check(Filename)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+} // namespace clang
diff --git a/clang/lib/Basic/ResourceSearch.cpp 
b/clang/lib/Basic/ResourceSearch.cpp
new file mode 100644
index 0000000000000..b9278d9b7f298
--- /dev/null
+++ b/clang/lib/Basic/ResourceSearch.cpp
@@ -0,0 +1,107 @@
+//===--- ResourceSearch.h - Searching for Resources -------------*- C++ 
-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// User-provided filters include/exclude profile instrumentation in certain
+// functions or files.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/ResourceSearch.h"
+#include "clang/Basic/FileManager.h"
+
+namespace clang {
+
+template <typename Strings>
+OptionalFileEntryRef LookupFileWithImpl(StringRef Filename, bool isAngled,
+                                        bool OpenFile, FileManager &FM,
+                                        const Strings &SearchEntries,
+                                        OptionalFileEntryRef LookupFromFile) {
+  if (llvm::sys::path::is_absolute(Filename)) {
+    // lookup path or immediately fail
+    llvm::Expected<FileEntryRef> ShouldBeEntry = FM.getFileRef(
+        Filename, OpenFile, /*CacheFailure=*/true, /*IsText=*/false);
+    return llvm::expectedToOptional(std::move(ShouldBeEntry));
+  }
+
+  auto SeparateComponents = [](SmallVectorImpl<char> &LookupPath,
+                               StringRef StartingFrom, StringRef FileName,
+                               bool RemoveInitialFileComponentFromLookupPath) {
+    llvm::sys::path::native(StartingFrom, LookupPath);
+    if (RemoveInitialFileComponentFromLookupPath)
+      llvm::sys::path::remove_filename(LookupPath);
+    if (!LookupPath.empty() &&
+        !llvm::sys::path::is_separator(LookupPath.back())) {
+      LookupPath.push_back(llvm::sys::path::get_separator().front());
+    }
+    LookupPath.append(FileName.begin(), FileName.end());
+  };
+
+  // Otherwise, it's search time!
+  SmallString<512> LookupPath;
+  // Non-angled lookup
+  if (!isAngled) {
+    // Use file-based lookup.
+    if (LookupFromFile) {
+      SmallString<1024> TmpDir;
+      TmpDir = LookupFromFile->getDir().getName();
+      llvm::sys::path::append(TmpDir, Filename);
+      if (!TmpDir.empty()) {
+        llvm::Expected<FileEntryRef> ShouldBeEntry = FM.getFileRef(
+            TmpDir, OpenFile, /*CacheFailure=*/true, /*IsText=*/false);
+        if (ShouldBeEntry)
+          return llvm::expectedToOptional(std::move(ShouldBeEntry));
+        llvm::consumeError(ShouldBeEntry.takeError());
+      }
+    }
+
+    // Otherwise, do working directory lookup.
+    LookupPath.clear();
+    auto MaybeWorkingDirEntry = FM.getDirectoryRef(".");
+    if (MaybeWorkingDirEntry) {
+      DirectoryEntryRef WorkingDirEntry = *MaybeWorkingDirEntry;
+      StringRef WorkingDir = WorkingDirEntry.getName();
+      if (!WorkingDir.empty()) {
+        SeparateComponents(LookupPath, WorkingDir, Filename, false);
+        llvm::Expected<FileEntryRef> ShouldBeEntry = FM.getFileRef(
+            LookupPath, OpenFile, /*CacheFailure=*/true, /*IsText=*/false);
+        if (ShouldBeEntry)
+          return llvm::expectedToOptional(std::move(ShouldBeEntry));
+        llvm::consumeError(ShouldBeEntry.takeError());
+      }
+    }
+  }
+
+  for (const auto &Entry : SearchEntries) {
+    LookupPath.clear();
+    SeparateComponents(LookupPath, Entry, Filename, false);
+    llvm::Expected<FileEntryRef> ShouldBeEntry = FM.getFileRef(
+        LookupPath, OpenFile, /*CacheFailure=*/true, /*IsText=*/false);
+    if (ShouldBeEntry)
+      return llvm::expectedToOptional(std::move(ShouldBeEntry));
+    llvm::consumeError(ShouldBeEntry.takeError());
+  }
+  return std::nullopt;
+}
+
+OptionalFileEntryRef
+LookupFileWithStdVec(StringRef Filename, bool isAngled, bool OpenFile,
+                     FileManager &FM,
+                     const std::vector<std::string> &SearchEntries,
+                     OptionalFileEntryRef LookupFromFile) {
+  return LookupFileWithImpl(Filename, isAngled, OpenFile, FM, SearchEntries,
+                            LookupFromFile);
+}
+
+OptionalFileEntryRef LookupFileWith(StringRef Filename, bool isAngled,
+                                    bool OpenFile, FileManager &FM,
+                                    ArrayRef<StringRef> SearchEntries,
+                                    OptionalFileEntryRef LookupFromFile) {
+  return LookupFileWithImpl(Filename, isAngled, OpenFile, FM, SearchEntries,
+                            LookupFromFile);
+}
+} // namespace clang
diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp
index 05ae1f348f920..450e44796cd6d 100644
--- a/clang/lib/Frontend/ASTUnit.cpp
+++ b/clang/lib/Frontend/ASTUnit.cpp
@@ -770,12 +770,13 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
       /*IILookup=*/nullptr,
       /*OwnsHeaderSearch=*/false);
 
-  if (ToLoad >= LoadASTOnly)
+  if (ToLoad >= LoadASTOnly) {
     AST->Ctx = llvm::makeIntrusiveRefCnt<ASTContext>(
         *AST->LangOpts, AST->getSourceManager(), AST->PP->getIdentifierTable(),
         AST->PP->getSelectorTable(), AST->PP->getBuiltinInfo(),
         AST->getTranslationUnitKind());
-
+    AST->Ctx->InputDependencyPatterns = AST->PP->InputDependencyPatterns;
+  }
   DisableValidationForModuleKind disableValid =
       DisableValidationForModuleKind::None;
   if (::getenv("LIBCLANG_DISABLE_PCH_VALIDATION"))
@@ -811,6 +812,9 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
     // Initialize the ASTContext
     AST->Ctx->InitBuiltinTypes(*AST->Target);
 
+    // Set preprocessor options
+    AST->Ctx->setCurrentPreprocessorOptions(AST->PP->getPreprocessorOpts());
+
     // Adjust printing policy based on language options.
     AST->Ctx->setPrintingPolicy(PrintingPolicy(*AST->LangOpts));
 
diff --git a/clang/lib/Frontend/CompilerInstance.cpp 
b/clang/lib/Frontend/CompilerInstance.cpp
index a504cde306a35..59ca450c6091d 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -556,6 +556,8 @@ void CompilerInstance::createASTContext() {
       getLangOpts(), PP.getSourceManager(), PP.getIdentifierTable(),
       PP.getSelectorTable(), PP.getBuiltinInfo(), PP.TUKind);
   Context->InitBuiltinTypes(getTarget(), getAuxTarget());
+  Context->setCurrentPreprocessorOptions(PP.getPreprocessorOpts());
+  Context->InputDependencyPatterns = PP.InputDependencyPatterns;
   setASTContext(std::move(Context));
 }
 
diff --git a/clang/lib/Frontend/DependencyFile.cpp 
b/clang/lib/Frontend/DependencyFile.cpp
index 64629abcaeb52..379aed3a2d7f5 100644
--- a/clang/lib/Frontend/DependencyFile.cpp
+++ b/clang/lib/Frontend/DependencyFile.cpp
@@ -12,6 +12,7 @@
 
 #include "clang/Basic/DiagnosticFrontend.h"
 #include "clang/Basic/FileManager.h"
+#include "clang/Basic/InputDependencyCollection.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Frontend/DependencyOutputOptions.h"
 #include "clang/Frontend/Utils.h"
@@ -101,6 +102,90 @@ struct DepCollectorPPCallbacks : public PPCallbacks {
     // Files that actually exist are handled by FileChanged.
   }
 
+  enum IsRecursive : bool {
+    Flat = false,
+    Recursive = true
+  };
+
+  static inline void DoSearch(FileManager& FM, const PatternFilter& Filter, 
DependencyCollector& DepCollector, StringRef Dir, IsRecursive Recurse) {
+    std::error_code EC;
+    for (llvm::vfs::directory_iterator FileIt = 
FM.getVirtualFileSystem().dir_begin(Dir, EC), FileEnd = {};
+          FileIt != FileEnd && !EC; FileIt.increment(EC)) {
+      const auto &File = *FileIt;
+      switch (File.type()) {
+      case llvm::sys::fs::file_type::directory_file: {
+        if (Recurse) {
+          DoSearch(FM, Filter, DepCollector, File.path(), Recurse);
+        }
+        break;
+      }
+      case llvm::sys::fs::file_type::regular_file: {
+        StringRef Filename = File.path();
+        if (Filter.Check(Filename)) {
+          DepCollector.maybeAddDependency(Filename,
+                                          /*FromModule*/ false,
+                                          /*IsSystem*/ false,
+                                          /*IsModuleFile*/ false,
+                                          /*IsMissing*/ false);
+        }
+        break;
+      }
+      default:
+        // do nothing
+        break;
+      }
+    }
+  }
+
+  void DependDirective(SourceLocation HashLoc, const Token &DependTok,
+                       StringRef Pattern, bool IsAngled,
+                       const PatternFilter &Filter,
+                       OptionalFileEntryRef CurrentFile) override {
+    if (Pattern.empty())
+      return;
+    FileManager& FM = PP.getFileManager();
+    llvm::vfs::FileSystem& VFS = FM.getVirtualFileSystem();
+    if (Filter.SearchRoot.empty()) {
+      // nothing we can do for ourselves here, just check the file directly and
+      // leave
+      if (Filter.RootHandling == RootPatternScanType::None) {
+        // it's either a directory or a file; add the dependency as-is
+        DepCollector.maybeAddDependency(Filter.Input,
+                                        /*FromModule*/ false,
+                                        /*IsSystem*/ false,
+                                        /*IsModuleFile*/ false,
+                                        /*IsMissing*/ 
!VFS.exists(Filter.Pattern));
+        return;
+      }
+      // if there's no search root, simply search from the current file's
+      // working directory (if it's quoted)
+      if (!IsAngled && CurrentFile) {
+        StringRef CurrentDir = CurrentFile->getDir().getName();
+        DoSearch(FM, Filter, DepCollector, CurrentDir, Filter.RootHandling == 
RootPatternScanType::Directory ? Flat : Recursive);
+      }
+      return;
+    }
+    // Otherwise, it's not empty. Note that we pre-computed the roots according
+    // to the compiler driver's resource/embed directory arguments previously,
+    // so we just need to do a singular check-if-exists-and-fire here.
+    if (Filter.RootHandling == RootPatternScanType::None) {
+      // treat as a single file, do a lookup and mark it for approval.
+      if (VFS.exists(Filter.Pattern)) {
+        // If it exists, it's what the user meant.
+        DepCollector.maybeAddDependency(Filter.Pattern,
+                                        /*FromModule*/ false,
+                                        /*IsSystem*/ false,
+                                        /*IsModuleFile*/ false,
+                                        /*IsMissing*/ false);
+      }
+    } else {
+      if (VFS.exists(Filter.PatternRoot)) {
+        DoSearch(FM, Filter, DepCollector, Filter.PatternRoot,
+          Filter.RootHandling == RootPatternScanType::Directory ? Flat : 
Recursive);
+      }
+    }
+  }
+
   void HasEmbed(SourceLocation, StringRef, bool,
                 OptionalFileEntryRef File) override {
     if (!File)
@@ -160,8 +245,8 @@ struct DepCollectorASTListener : public ASTReaderListener {
                                     /*IsSystem*/ false, /*IsModuleFile*/ true,
                                     /*IsMissing*/ false);
   }
-  bool visitInputFile(StringRef Filename, bool IsSystem,
-                      bool IsOverridden, bool IsExplicitModule) override {
+  bool visitInputFile(StringRef Filename, bool IsSystem, bool IsOverridden,
+                      bool IsExplicitModule) override {
     if (IsOverridden || IsExplicitModule)
       return true;
 
@@ -216,7 +301,7 @@ bool DependencyCollector::sawDependency(StringRef Filename, 
bool FromModule,
          (needSystemDependencies() || !IsSystem);
 }
 
-DependencyCollector::~DependencyCollector() { }
+DependencyCollector::~DependencyCollector() {}
 void DependencyCollector::attachToPreprocessor(Preprocessor &PP) {
   PP.addPPCallbacks(std::make_unique<DepCollectorPPCallbacks>(*this, PP));
   PP.getHeaderSearchInfo().getModuleMap().addModuleMapCallbacks(
diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp
index b90c04776ff9e..b932f2b1dc3cf 100644
--- a/clang/lib/Lex/PPDirectives.cpp
+++ b/clang/lib/Lex/PPDirectives.cpp
@@ -19,6 +19,7 @@
 #include "clang/Basic/IdentifierTable.h"
 #include "clang/Basic/LangOptions.h"
 #include "clang/Basic/Module.h"
+#include "clang/Basic/ResourceSearch.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Basic/TargetInfo.h"
@@ -1193,72 +1194,8 @@ OptionalFileEntryRef 
Preprocessor::LookupEmbedFile(StringRef Filename,
                                                    bool isAngled,
                                                    bool OpenFile) {
   FileManager &FM = this->getFileManager();
-  if (llvm::sys::path::is_absolute(Filename)) {
-    // lookup path or immediately fail
-    llvm::Expected<FileEntryRef> ShouldBeEntry = FM.getFileRef(
-        Filename, OpenFile, /*CacheFailure=*/true, /*IsText=*/false);
-    return llvm::expectedToOptional(std::move(ShouldBeEntry));
-  }
-
-  auto SeparateComponents = [](SmallVectorImpl<char> &LookupPath,
-                               StringRef StartingFrom, StringRef FileName,
-                               bool RemoveInitialFileComponentFromLookupPath) {
-    llvm::sys::path::native(StartingFrom, LookupPath);
-    if (RemoveInitialFileComponentFromLookupPath)
-      llvm::sys::path::remove_filename(LookupPath);
-    if (!LookupPath.empty() &&
-        !llvm::sys::path::is_separator(LookupPath.back())) {
-      LookupPath.push_back(llvm::sys::path::get_separator().front());
-    }
-    LookupPath.append(FileName.begin(), FileName.end());
-  };
-
-  // Otherwise, it's search time!
-  SmallString<512> LookupPath;
-  // Non-angled lookup
-  if (!isAngled) {
-    OptionalFileEntryRef LookupFromFile = 
getCurrentFileLexer()->getFileEntry();
-    if (LookupFromFile) {
-      // Use file-based lookup.
-      SmallString<1024> TmpDir;
-      TmpDir = LookupFromFile->getDir().getName();
-      llvm::sys::path::append(TmpDir, Filename);
-      if (!TmpDir.empty()) {
-        llvm::Expected<FileEntryRef> ShouldBeEntry = FM.getFileRef(
-            TmpDir, OpenFile, /*CacheFailure=*/true, /*IsText=*/false);
-        if (ShouldBeEntry)
-          return llvm::expectedToOptional(std::move(ShouldBeEntry));
-        llvm::consumeError(ShouldBeEntry.takeError());
-      }
-    }
-
-    // Otherwise, do working directory lookup.
-    LookupPath.clear();
-    auto MaybeWorkingDirEntry = FM.getDirectoryRef(".");
-    if (MaybeWorkingDirEntry) {
-      DirectoryEntryRef WorkingDirEntry = *MaybeWorkingDirEntry;
-      StringRef WorkingDir = WorkingDirEntry.getName();
-      if (!WorkingDir.empty()) {
-        SeparateComponents(LookupPath, WorkingDir, Filename, false);
-        llvm::Expected<FileEntryRef> ShouldBeEntry = FM.getFileRef(
-            LookupPath, OpenFile, /*CacheFailure=*/true, /*IsText=*/false);
-        if (ShouldBeEntry)
-          return llvm::expectedToOptional(std::move(ShouldBeEntry));
-        llvm::consumeError(ShouldBeEntry.takeError());
-      }
-    }
-  }
-
-  for (const auto &Entry : PPOpts.EmbedEntries) {
-    LookupPath.clear();
-    SeparateComponents(LookupPath, Entry, Filename, false);
-    llvm::Expected<FileEntryRef> ShouldBeEntry = FM.getFileRef(
-        LookupPath, OpenFile, /*CacheFailure=*/true, /*IsText=*/false);
-    if (ShouldBeEntry)
-      return llvm::expectedToOptional(std::move(ShouldBeEntry));
-    llvm::consumeError(ShouldBeEntry.takeError());
-  }
-  return std::nullopt;
+  OptionalFileEntryRef LookupFromFileHere = 
getCurrentFileLexer()->getFileEntry();
+  return LookupFileWithStdVec(Filename, isAngled, OpenFile, FM, 
PPOpts.EmbedEntries, LookupFromFileHere);
 }
 
 
//===----------------------------------------------------------------------===//
@@ -1359,6 +1296,7 @@ void Preprocessor::HandleDirective(Token &Result) {
       case tok::pp___include_macros:
       case tok::pp_pragma:
       case tok::pp_embed:
+      case tok::pp_depend:
       case tok::pp_module:
       case tok::pp___preprocessed_module:
       case tok::pp___preprocessed_import:
@@ -1493,6 +1431,8 @@ void Preprocessor::HandleDirective(Token &Result) {
       return HandleIdentSCCSDirective(Result);
     case tok::pp_embed:
       return HandleEmbedDirective(Introducer.getLocation(), Result);
+    case tok::pp_depend:
+      return HandleDependDirective(Introducer.getLocation(), Result);
     case tok::pp_assert:
       //isExtension = true;  // FIXME: implement #assert
       break;
@@ -4181,6 +4121,62 @@ void Preprocessor::HandleEmbedDirective(SourceLocation 
HashLoc,
   HandleEmbedDirectiveImpl(HashLoc, *Params, BinaryContents, FilenameToGo);
 }
 
+void Preprocessor::HandleDependDirective(SourceLocation HashLoc,
+                                       Token &DependTok) {
+  // Give the usual extension/compatibility warnings.
+  Diag(DependTok, diag::ext_pp_depend_directive)
+        << /*Clang*/ 1;
+  // It's always a clang extension: it will become a C++2c extension after
+  // more WG21 work later. Remember to come back and tweak this!
+
+  // this unfortunately has no meaning but it's part of the grammar for the 
future so we should parse it normally
+  bool IsExported = false;
+  Token PatternTok;
+  Lex(PatternTok);
+  if (PatternTok.is(tok::kw_export)) {
+      IsExported = true;
+  }
+
+  // Parse the pattern header-name, with a potential first skip
+  if (LexHeaderName(PatternTok, true, !IsExported)) {
+    return;
+  }
+
+  if (PatternTok.isNot(tok::header_name)) {
+    Diag(PatternTok.getLocation(), diag::err_pp_expects_pattern);
+    if (PatternTok.isNot(tok::eod))
+      DiscardUntilEndOfDirective();
+    return;
+  }
+
+  Token EoDTok;
+  LexNonComment(EoDTok);
+  if (!EoDTok.isNot(tok::eod) && !EoDTok.isNot(tok::eof)) {
+    Diag(PatternTok.getLocation(), diag::err_pp_expected_eol);
+    DiscardUntilEndOfDirective();
+    return;
+  }
+  
+  
+  SmallString<256> PatternBuffer;
+  StringRef Pattern = getSpelling(PatternTok, PatternBuffer);
+  bool IsAngled =
+      GetIncludeFilenameSpelling(PatternTok.getLocation(), Pattern);
+  // Every pattern is local to where it was found, so prepend the current
+  // directory of the file if it's a non-absolute path from the perspective of
+  // this current header file
+  OptionalFileEntryRef CurrentFile = std::nullopt;
+  if (IsFileLexer()) {
+    PreprocessorLexer *ThisFileLexer = getCurrentFileLexer();
+    FileID ThisFID = ThisFileLexer->getFileID();
+    CurrentFile = SourceMgr.getFileEntryRefForID(ThisFID);
+  }
+  const PatternFilter& Filter
+    = InputDependencyPatterns->Add(Pattern.str(), IsAngled, IsExported, 
getFileManager(), PPOpts.EmbedEntries, CurrentFile);
+  if (Callbacks)
+    Callbacks->DependDirective(HashLoc, DependTok, Pattern, IsAngled, Filter, 
CurrentFile);
+}
+
 /// HandleCXXImportDirective - Handle the C++ modules import directives
 ///
 /// pp-import:
diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp
index c430da67c1469..8f17af97f551b 100644
--- a/clang/lib/Lex/Preprocessor.cpp
+++ b/clang/lib/Lex/Preprocessor.cpp
@@ -1090,18 +1090,20 @@ void Preprocessor::LexTokensUntilEOF(std::vector<Token> 
*Tokens) {
 ///        token is a '<').
 /// \return \c true if we reached EOD or EOF while looking for a > token in
 ///         a concatenated header name and diagnosed it. \c false otherwise.
-bool Preprocessor::LexHeaderName(Token &FilenameTok, bool AllowMacroExpansion) 
{
+bool Preprocessor::LexHeaderName(Token &FilenameTok, bool AllowMacroExpansion, 
bool SkipFirst) {
   // Lex using header-name tokenization rules if tokens are being lexed from
   // a file. Just grab a token normally if we're in a macro expansion.
-  if (CurPPLexer) {
-    // Avoid nested header-name lexing when macro expansion recurses
-    // __has_include(__has_include))
-    if (CurPPLexer->ParsingFilename)
-      LexUnexpandedToken(FilenameTok);
-    else
-      CurPPLexer->LexIncludeFilename(FilenameTok);
-  } else {
-    Lex(FilenameTok);
+  if (!SkipFirst) {
+    if (CurPPLexer) {
+      // Avoid nested header-name lexing when macro expansion recurses
+      // __has_include(__has_include))
+      if (CurPPLexer->ParsingFilename)
+        LexUnexpandedToken(FilenameTok);
+      else
+        CurPPLexer->LexIncludeFilename(FilenameTok);
+    } else {
+      Lex(FilenameTok);
+    }
   }
 
   // This could be a <foo/bar.h> file coming from a macro expansion.  In this
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 1c1cd0f292753..e08ecc71dd19d 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -3843,6 +3843,13 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, 
unsigned BuiltinID,
     if (BuiltinCountedByRef(TheCall))
       return ExprError();
     break;
+  case Builtin::BI__builtin_std_embed:
+    // while we do not have Custom Typechecking,
+    // we have a `...` signature, so we do need to
+    // at least gently inspect some of the arguments
+    if (BuiltinStdEmbed(TheCall))
+      return ExprError();
+    break;
   }
 
   if (getLangOpts().HLSL && HLSL().CheckBuiltinFunctionCall(BuiltinID, 
TheCall))
@@ -6668,6 +6675,150 @@ bool Sema::BuiltinCountedByRef(CallExpr *TheCall) {
   return false;
 }
 
+bool Sema::BuiltinStdEmbed(CallExpr *TheCall) {
+  const bool HasProperArgCount = !checkArgCountAtLeast(TheCall, 5);
+  const bool HasExtraLimitArg = !checkArgCountAtMost(TheCall, 6) && 
TheCall->getNumArgs() == 6;
+  if (!HasProperArgCount && !HasExtraLimitArg)
+    return true;
+
+  const Expr *SizeRef = TheCall->getArg(0);
+  const Expr *PtrRef = TheCall->getArg(1);
+  const unsigned int ResourceNameSizeIndex = 2;
+  const Expr *ResourceNameSize = TheCall->getArg(ResourceNameSizeIndex);
+  const unsigned int ResourceNamePtrIndex = 3;
+  const Expr *ResourceNamePtr = TheCall->getArg(ResourceNamePtrIndex);
+  const unsigned int OffsetIndex = 4;
+  const Expr *Offset = TheCall->getArg(OffsetIndex);
+  const unsigned int LimitIndex = 5;
+  const Expr *Limit = HasExtraLimitArg ? TheCall->getArg(LimitIndex) : nullptr;
+
+  // Size argument type
+  QualType SizeRefTy = SizeRef->getType();
+  if ((!SizeRefTy->isIntegralOrUnscopedEnumerationType())
+      || SizeRefTy.isConstant(Context)
+      || !SizeRef->isLValue()) {
+    Diag(TheCall->getBeginLoc(), diag::err_invalid_builtin_argument)
+      << SizeRef << "__builtin_std_embed"
+      << SizeRef->getSourceRange();
+    return true;
+  }
+
+  // value pointer, has to be non-constant (but pointer to `const`).
+  // tells us what the type for the builtin return is, serves no other purpose.
+  QualType PtrRefTy = PtrRef->getType();
+  if (!PtrRefTy->isPointerType()) {
+    Diag(TheCall->getBeginLoc(), diag::err_invalid_builtin_argument)
+      << PtrRefTy << "__builtin_std_embed"
+      << PtrRef->getSourceRange();
+    return true;
+  }
+  QualType ArrElementTy = PtrRefTy->getPointeeType();
+  if (!ArrElementTy.isConstant(Context)) {
+    Diag(TheCall->getBeginLoc(), diag::err_invalid_builtin_argument)
+      << PtrRef << "__builtin_std_embed"
+      << PtrRef->getSourceRange();
+    return true;
+  }
+
+  const uint64_t CharSize = Context.getCharWidth();
+  if (!(ArrElementTy->isIntegralOrEnumerationType()
+        && Context.getTypeSize(ArrElementTy) == CharSize
+        && Context.getTypeAlign(ArrElementTy) == CharSize)) {
+    Diag(TheCall->getBeginLoc(), diag::err_invalid_builtin_argument)
+      << PtrRef << "__builtin_std_embed"
+      << PtrRef->getSourceRange();
+    return true;
+  }
+
+  // Next argument is size of the string
+  const QualType SizeType = Context.getSizeType();
+  QualType ResourceNameSizeTy = ResourceNameSize->getType();
+  if (!ResourceNameSizeTy->isIntegralOrEnumerationType()) {
+    Expr *ResourceNameSizeMutable = const_cast<Expr *>(ResourceNameSize);
+    ExprResult ImplicitResourceNameSizeFixupResult = 
PerformImplicitConversion(ResourceNameSizeMutable, SizeType, 
AssignmentAction::Passing);
+    if (!ImplicitResourceNameSizeFixupResult.isUsable()) {
+      Diag(TheCall->getBeginLoc(), 
diag::err_typecheck_converted_constant_expression)
+        << ResourceNameSizeTy << SizeType;
+      return true;
+    }
+    // The implicit conversion worked -- adjust the builtin's argument.
+    TheCall->setArg(ResourceNameSizeIndex, 
ImplicitResourceNameSizeFixupResult.get());
+  }
+
+  // Pointer to an appropriate string type
+  // (char, wchar_t, or char8_t)
+  QualType ResourceNamePtrTy = ResourceNamePtr->getType();
+  if (!ResourceNamePtrTy->isPointerType()) {
+    const QualType AllowedTypes[3] = {
+      Context.getPointerType(Context.CharTy),
+      Context.getPointerType(Context.WCharTy),
+      Context.getPointerType(Context.Char8Ty)
+    };
+    Expr *ResourceNamePtrMutable =  const_cast<Expr *>(ResourceNamePtr);
+    ExprResult ImplicitResourceNamePtrFixupResult;
+    for (const QualType& DesiredType : AllowedTypes) {
+      ImplicitResourceNamePtrFixupResult = 
PerformImplicitConversion(ResourceNamePtrMutable, DesiredType, 
AssignmentAction::Passing);
+      if (ImplicitResourceNamePtrFixupResult.isUsable()) {
+        break;
+      }
+    }
+    if (!ImplicitResourceNamePtrFixupResult.isUsable()) {
+      Diag(ResourceNamePtr->getBeginLoc(), 
diag::err_typecheck_converted_constant_expression)
+         << ResourceNamePtrTy << "a pointer to char, wchar_t, or char8_t";
+      return true;
+    }
+    TheCall->setArg(ResourceNamePtrIndex, 
ImplicitResourceNamePtrFixupResult.get());
+    ResourceNamePtr = TheCall->getArg(ResourceNamePtrIndex);
+    ResourceNamePtrTy = ResourceNamePtr->getType();
+  }
+  QualType 
ResourceNameCharTy(ResourceNamePtrTy->getPointeeOrArrayElementType(), 0);
+  if (!ResourceNameCharTy->isCharType()
+      && !ResourceNameCharTy->isChar8Type()
+      && !ResourceNameCharTy->isWideCharType()) {
+      Diag(ResourceNamePtr->getBeginLoc(), 
diag::err_typecheck_convert_incompatible_pointer)
+        << 1 << 1 << 1 << 0;
+      return true;
+    
+  }
+
+  // Check the integer-convertible argument is offset
+  QualType OffsetTy = Offset->getType();
+  if (!OffsetTy->isIntegralOrEnumerationType()) {
+    Expr *OffsetMutable =  const_cast<Expr *>(Offset);
+    ExprResult ImplicitOffsetFixupResult = 
PerformImplicitConversion(OffsetMutable, SizeType, AssignmentAction::Passing);
+    if (!ImplicitOffsetFixupResult.isUsable()) {
+      Diag(TheCall->getBeginLoc(), 
diag::err_typecheck_converted_constant_expression)
+        << ResourceNameSizeTy << SizeType;
+      return true;
+    }
+    // The implicit conversion worked -- adjust the builtin's argument.
+    TheCall->setArg(OffsetIndex, ImplicitOffsetFixupResult.get());
+  }
+
+  if (HasExtraLimitArg) {
+    // If present, final argument is offset
+    QualType LimitTy = Limit->getType();
+    if (!LimitTy->isIntegralOrEnumerationType()) {
+      Expr *LimitMutable =  const_cast<Expr *>(Limit);
+      ExprResult ImplicitLimitFixupResult = 
PerformImplicitConversion(LimitMutable, SizeType, AssignmentAction::Passing);
+      if (!ImplicitLimitFixupResult.isUsable()) {
+        Diag(TheCall->getBeginLoc(), 
diag::err_typecheck_converted_constant_expression)
+        << ResourceNameSizeTy << SizeType;
+        return true;
+      }
+      // The implicit conversion worked -- adjust the builtin's argument.
+      TheCall->setArg(LimitIndex, ImplicitLimitFixupResult.get());
+    }
+  }
+
+  // return the same type as was put in; we don't actually do anything with
+  // the pointer-reference type other than to use it for
+  // proper typesetting.
+  TheCall->setType(PtrRefTy);
+
+  return false;
+}
+
 /// The result of __builtin_counted_by_ref cannot be assigned to a variable.
 /// It allows leaking and modification of bounds safety information.
 bool Sema::CheckInvalidBuiltinCountedByRef(const Expr *E,
diff --git a/clang/tools/clang-import-test/clang-import-test.cpp 
b/clang/tools/clang-import-test/clang-import-test.cpp
index 8e83687d3e96a..2234f44c0611a 100644
--- a/clang/tools/clang-import-test/clang-import-test.cpp
+++ b/clang/tools/clang-import-test/clang-import-test.cpp
@@ -229,6 +229,8 @@ BuildASTContext(CompilerInstance &CI, SelectorTable &ST, 
Builtin::Context &BC) {
       CI.getLangOpts(), CI.getSourceManager(),
       PP.getIdentifierTable(), ST, BC, PP.TUKind);
   AST->InitBuiltinTypes(CI.getTarget());
+  AST->setCurrentPreprocessorOptions(PP.getPreprocessorOpts());
+  AST->InputDependencyPatterns = PP.InputDependencyPatterns;
   return AST;
 }
 
diff --git a/clang/unittests/Lex/PPCallbacksTest.cpp 
b/clang/unittests/Lex/PPCallbacksTest.cpp
index 9533fbc776e6e..f3b89db0be8c1 100644
--- a/clang/unittests/Lex/PPCallbacksTest.cpp
+++ b/clang/unittests/Lex/PPCallbacksTest.cpp
@@ -311,6 +311,7 @@ class PPCallbacksTest : public ::testing::Test {
     ASTContext Context(OpenCLLangOpts, SourceMgr, PP.getIdentifierTable(),
                        PP.getSelectorTable(), PP.getBuiltinInfo(), PP.TUKind);
     Context.InitBuiltinTypes(*Target);
+    Context.setCurrentPreprocessorOptions(PP.getPreprocessorOpts());
 
     ASTConsumer Consumer;
     Sema S(PP, Context, Consumer);
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 53165f0336b2d..c86b6e5288d7c 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -1007,6 +1007,7 @@ set(files
   cwchar
   cwctype
   deque
+  embed
   errno.h
   exception
   execution
diff --git a/libcxx/include/embed b/libcxx/include/embed
new file mode 100644
index 0000000000000..e434433ff5b11
--- /dev/null
+++ b/libcxx/include/embed
@@ -0,0 +1,113 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef _LIBCPP_EMBED
+#define _LIBCPP_EMBED
+
+/*
+    embed synopsis
+
+namespace std {
+
+  template <typename T>
+consteval span<const T> embed(string_view resource_idenfier,
+  size_t offset = 0,
+  optional<size_t> limit = nullopt);
+
+  template <typename T>
+consteval span<const T> embed(wstring_view resource_idenfier,
+  size_t offset = 0,
+  optional<size_t> limit = nullopt);
+
+  template <typename T>
+consteval span<const T> embed(u8string_view resource_idenfier,
+  size_t offset = 0,
+  optional<size_t> limit = nullopt);
+
+} // namespace std
+
+*/
+
+#if __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
+#  include <__cxx03/__config>
+#else
+#  include <__config>
+#  include <__cstddef/byte.h>
+#  include <__type_traits/is_enum.h>
+#  include <__type_traits/is_integral.h>
+#  include <__type_traits/is_same.h>
+#  include <optional>
+#  include <span>
+#  include <string_view>
+#  include <version>
+
+#  if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#    pragma GCC system_header
+#  endif
+
+_LIBCPP_PUSH_MACROS
+#  include <__undef_macros>
+
+#  if !defined(_LIBCPP_HAS_EMBED)
+#    if __has_builtin(__builtin_std_embed)
+#      define _LIBCPP_HAS_EMBED 1
+#    else
+#      define _LIBCPP_HAS_EMBED 0
+#    endif
+#  endif
+
+#  if _LIBCPP_HAS_EMBED != 0
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+namespace __embed_detail {
+template <typename _Byte, typename _StrView>
+consteval span<const _Byte>
+__embed(const _StrView& __resource_identifier, size_t __offset = 0, 
optional<size_t> __limit = nullopt) {
+  static_assert(sizeof(_Byte) == 1 && alignof(_Byte) == 1 && 
(is_integral<_Byte>::value || is_enum<_Byte>::value),
+                "embed data type must be a character type with a size and 
alignment of 1");
+  size_t __size      = 0;
+  _Byte const* __ptr = nullptr;
+  if (__limit) {
+    __ptr = __builtin_std_embed(
+        __size, __ptr, __resource_identifier.size(), 
__resource_identifier.data(), __offset, *__limit);
+  } else {
+    __ptr = __builtin_std_embed(__size, __ptr, __resource_identifier.size(), 
__resource_identifier.data(), __offset);
+  }
+  return span<const _Byte>(__ptr, __size);
+}
+} // namespace __embed_detail
+
+template <typename _Byte>
+consteval span<const _Byte>
+embed(string_view __resource_identifier, size_t __offset = 0, optional<size_t> 
__limit = nullopt) {
+  return __embed_detail::__embed<_Byte>(__resource_identifier, __offset, 
__limit);
+}
+
+template <typename _Byte>
+consteval span<const _Byte>
+embed(wstring_view __resource_identifier, size_t __offset = 0, 
optional<size_t> __limit = nullopt) {
+  return __embed_detail::__embed<_Byte>(__resource_identifier, __offset, 
__limit);
+}
+
+template <typename _Byte>
+consteval span<const _Byte>
+embed(u8string_view __resource_identifier, size_t __offset = 0, 
optional<size_t> __limit = nullopt) {
+  return __embed_detail::__embed<_Byte>(__resource_identifier, __offset, 
__limit);
+}
+
+_LIBCPP_END_NAMESPACE_STD
+
+#  endif
+
+_LIBCPP_POP_MACROS
+
+#endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
+
+#endif // _LIBCPP_EMBED
diff --git a/libcxx/include/version b/libcxx/include/version
index c43d36e569efb..e270a935fddcd 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -632,6 +632,13 @@ __cpp_lib_void_t                                        
201411L <type_traits>
 # define __cpp_lib_variant                              202306L
 #endif
 
+#if _LIBCPP_STD_VER >= 23
+# if __has_builtin(__builtin_std_embed) || (defined(_LIBCPP_HAS_EMBED) && 
(_LIBCPP_HAS_EMBED != 0))
+#   define __cpp_lib_embed                                 202607L
+# endif
+#endif
+
+
 #endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
 
 // clang-format on

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

Reply via email to