llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-hlsl

Author: Helena Kotas (hekota)

<details>
<summary>Changes</summary>

Moving builder classes into separate files 
`HLSLBuiltinTypeDeclBuilder.cpp`/`.h`, changing a some `HLSLExternalSemaSource` 
methods to private and removing unused methods.

This is a prep work before we start adding more builtin types and methods, like 
textures, resource constructors or matrices. For example constructors could 
make use of the `BuiltinTypeMethodBuilder`, but this helper class was defined 
in `HLSLExternalSemaSource.cpp` after the method that creates a constructor. 
Rather than reshuffling the code one big source file I am moving the builders 
into a separate cpp &amp; header file and placing the helper classes 
declarations up top.

Currently the new header only exposes `BuiltinTypeDeclBuilder` to 
`HLSLExternalSemaSource`. In the future but we might decide to expose more 
helper classes as needed.

---

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


5 Files Affected:

- (modified) clang/include/clang/Sema/HLSLExternalSemaSource.h (+8-7) 
- (modified) clang/lib/Sema/CMakeLists.txt (+1) 
- (added) clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp (+782) 
- (added) clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h (+96) 
- (modified) clang/lib/Sema/HLSLExternalSemaSource.cpp (+2-748) 


``````````diff
diff --git a/clang/include/clang/Sema/HLSLExternalSemaSource.h 
b/clang/include/clang/Sema/HLSLExternalSemaSource.h
index 3c7495e66055d..9c1b16ba3950c 100644
--- a/clang/include/clang/Sema/HLSLExternalSemaSource.h
+++ b/clang/include/clang/Sema/HLSLExternalSemaSource.h
@@ -21,20 +21,15 @@ class NamespaceDecl;
 class Sema;
 
 class HLSLExternalSemaSource : public ExternalSemaSource {
+private:
   Sema *SemaPtr = nullptr;
   NamespaceDecl *HLSLNamespace = nullptr;
 
   using CompletionFunction = std::function<void(CXXRecordDecl *)>;
   llvm::DenseMap<CXXRecordDecl *, CompletionFunction> Completions;
 
-  void defineHLSLVectorAlias();
-  void defineTrivialHLSLTypes();
-  void defineHLSLTypesWithForwardDeclarations();
-
-  void onCompletion(CXXRecordDecl *Record, CompletionFunction Fn);
-
 public:
-  ~HLSLExternalSemaSource() override;
+  ~HLSLExternalSemaSource() override {}
 
   /// Initialize the semantic source with the Sema instance
   /// being used to perform semantic analysis on the abstract syntax
@@ -47,6 +42,12 @@ class HLSLExternalSemaSource : public ExternalSemaSource {
   using ExternalASTSource::CompleteType;
   /// Complete an incomplete HLSL builtin type
   void CompleteType(TagDecl *Tag) override;
+
+private:
+  void defineTrivialHLSLTypes();
+  void defineHLSLVectorAlias();
+  void defineHLSLTypesWithForwardDeclarations();
+  void onCompletion(CXXRecordDecl *Record, CompletionFunction Fn);
 };
 
 } // namespace clang
diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt
index 1a351684d133e..d3fe80f659f69 100644
--- a/clang/lib/Sema/CMakeLists.txt
+++ b/clang/lib/Sema/CMakeLists.txt
@@ -20,6 +20,7 @@ add_clang_library(clangSema
   DeclSpec.cpp
   DelayedDiagnostic.cpp
   HeuristicResolver.cpp
+  HLSLBuiltinTypeDeclBuilder.cpp
   HLSLExternalSemaSource.cpp
   IdentifierResolver.cpp
   JumpDiagnostics.cpp
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp 
b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
new file mode 100644
index 0000000000000..db0ed3434d837
--- /dev/null
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -0,0 +1,782 @@
+//===--- HLSLBuiltinTypeDeclBuilder.cpp - HLSL Builtin Type Decl Builder 
--===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+//
+//===----------------------------------------------------------------------===//
+
+#include "HLSLBuiltinTypeDeclBuilder.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaHLSL.h"
+#include "llvm/ADT/SmallVector.h"
+
+using namespace llvm::hlsl;
+
+namespace clang {
+
+namespace hlsl {
+
+namespace {
+
+static FunctionDecl *lookupBuiltinFunction(Sema &S, StringRef Name) {
+  IdentifierInfo &II =
+      S.getASTContext().Idents.get(Name, tok::TokenKind::identifier);
+  DeclarationNameInfo NameInfo =
+      DeclarationNameInfo(DeclarationName(&II), SourceLocation());
+  LookupResult R(S, NameInfo, Sema::LookupOrdinaryName);
+  // AllowBuiltinCreation is false but LookupDirect will create
+  // the builtin when searching the global scope anyways...
+  S.LookupName(R, S.getCurScope());
+  // FIXME: If the builtin function was user-declared in global scope,
+  // this assert *will* fail. Should this call LookupBuiltin instead?
+  assert(R.isSingleResult() &&
+         "Since this is a builtin it should always resolve!");
+  return cast<FunctionDecl>(R.getFoundDecl());
+}
+} // namespace
+
+// Builder for template arguments of builtin types. Used internally
+// by BuiltinTypeDeclBuilder.
+struct TemplateParameterListBuilder {
+  BuiltinTypeDeclBuilder &Builder;
+  llvm::SmallVector<NamedDecl *> Params;
+
+  TemplateParameterListBuilder(BuiltinTypeDeclBuilder &RB) : Builder(RB) {}
+  ~TemplateParameterListBuilder();
+
+  TemplateParameterListBuilder &
+  addTypeParameter(StringRef Name, QualType DefaultValue = QualType());
+
+  ConceptSpecializationExpr *
+  constructConceptSpecializationExpr(Sema &S, ConceptDecl *CD);
+
+  BuiltinTypeDeclBuilder &finalizeTemplateArgs(ConceptDecl *CD = nullptr);
+};
+
+// Builder for methods of builtin types. Allows adding methods to builtin types
+// using the builder pattern like this:
+//
+//   BuiltinTypeMethodBuilder(RecordBuilder, "MethodName", ReturnType)
+//       .addParam("param_name", Type, InOutModifier)
+//       .callBuiltin("builtin_name", BuiltinParams...)
+//       .finalizeMethod();
+//
+// The builder needs to have all of the method parameters before it can create
+// a CXXMethodDecl. It collects them in addParam calls and when a first
+// method that builds the body is called or when access to 'this` is needed it
+// creates the CXXMethodDecl and ParmVarDecls instances. These can then be
+// referenced from the body building methods. Destructor or an explicit call to
+// finalizeMethod() will complete the method definition.
+//
+// The callBuiltin helper method accepts constants via `Expr *` or placeholder
+// value arguments to indicate which function arguments to forward to the
+// builtin.
+//
+// If the method that is being built has a non-void return type the
+// finalizeMethod will create a return statent with the value of the last
+// statement (unless the last statement is already a ReturnStmt).
+struct BuiltinTypeMethodBuilder {
+private:
+  struct MethodParam {
+    const IdentifierInfo &NameII;
+    QualType Ty;
+    HLSLParamModifierAttr::Spelling Modifier;
+    MethodParam(const IdentifierInfo &NameII, QualType Ty,
+                HLSLParamModifierAttr::Spelling Modifier)
+        : NameII(NameII), Ty(Ty), Modifier(Modifier) {}
+  };
+
+  BuiltinTypeDeclBuilder &DeclBuilder;
+  DeclarationNameInfo NameInfo;
+  QualType ReturnTy;
+  CXXMethodDecl *Method;
+  bool IsConst;
+  llvm::SmallVector<MethodParam> Params;
+  llvm::SmallVector<Stmt *> StmtsList;
+
+  // Argument placeholders, inspired by std::placeholder. These are the indices
+  // of arguments to forward to `callBuiltin` and other method builder methods.
+  // Additional special values are:
+  //   Handle   - refers to the resource handle.
+  //   LastStmt - refers to the last statement in the method body; referencing
+  //              LastStmt will remove the statement from the method body since
+  //              it will be linked from the new expression being constructed.
+  enum class PlaceHolder { _0, _1, _2, _3, Handle = 128, LastStmt };
+
+  Expr *convertPlaceholder(PlaceHolder PH);
+  Expr *convertPlaceholder(Expr *E) { return E; }
+
+public:
+  friend BuiltinTypeDeclBuilder;
+
+  BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, DeclarationName &Name,
+                           QualType ReturnTy, bool IsConst = false)
+      : DeclBuilder(DB), NameInfo(DeclarationNameInfo(Name, SourceLocation())),
+        ReturnTy(ReturnTy), Method(nullptr), IsConst(IsConst) {}
+
+  BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, StringRef Name,
+                           QualType ReturnTy, bool IsConst = false);
+  BuiltinTypeMethodBuilder(const BuiltinTypeMethodBuilder &Other) = delete;
+
+  ~BuiltinTypeMethodBuilder() { finalizeMethod(); }
+
+  BuiltinTypeMethodBuilder &
+  operator=(const BuiltinTypeMethodBuilder &Other) = delete;
+
+  BuiltinTypeMethodBuilder &addParam(StringRef Name, QualType Ty,
+                                     HLSLParamModifierAttr::Spelling Modifier =
+                                         HLSLParamModifierAttr::Keyword_in);
+  template <typename... Ts>
+  BuiltinTypeMethodBuilder &callBuiltin(StringRef BuiltinName,
+                                        QualType ReturnType, Ts... ArgSpecs);
+  template <typename TLHS, typename TRHS>
+  BuiltinTypeMethodBuilder &assign(TLHS LHS, TRHS RHS);
+  template <typename T> BuiltinTypeMethodBuilder &dereference(T Ptr);
+  BuiltinTypeDeclBuilder &finalizeMethod();
+  Expr *getResourceHandleExpr();
+
+private:
+  void createMethodDecl();
+};
+
+TemplateParameterListBuilder::~TemplateParameterListBuilder() {
+  finalizeTemplateArgs();
+}
+
+TemplateParameterListBuilder &
+TemplateParameterListBuilder::addTypeParameter(StringRef Name,
+                                               QualType DefaultValue) {
+  assert(!Builder.Record->isCompleteDefinition() &&
+         "record is already complete");
+  ASTContext &AST = Builder.SemaRef.getASTContext();
+  unsigned Position = static_cast<unsigned>(Params.size());
+  auto *Decl = TemplateTypeParmDecl::Create(
+      AST, Builder.Record->getDeclContext(), SourceLocation(), 
SourceLocation(),
+      /* TemplateDepth */ 0, Position,
+      &AST.Idents.get(Name, tok::TokenKind::identifier),
+      /* Typename */ true,
+      /* ParameterPack */ false,
+      /* HasTypeConstraint*/ false);
+  if (!DefaultValue.isNull())
+    Decl->setDefaultArgument(AST,
+                             Builder.SemaRef.getTrivialTemplateArgumentLoc(
+                                 DefaultValue, QualType(), SourceLocation()));
+
+  Params.emplace_back(Decl);
+  return *this;
+}
+
+// The concept specialization expression (CSE) constructed in
+// constructConceptSpecializationExpr is constructed so that it
+// matches the CSE that is constructed when parsing the below C++ code:
+//
+// template<typename T>
+// concept is_typed_resource_element_compatible =
+// __builtin_hlsl_typed_resource_element_compatible<T>
+//
+// template<typename element_type> requires
+// is_typed_resource_element_compatible<element_type>
+// struct RWBuffer {
+//     element_type Val;
+// };
+//
+// int fn() {
+//     RWBuffer<int> Buf;
+// }
+//
+// When dumping the AST and filtering for "RWBuffer", the resulting AST
+// structure is what we're trying to construct below, specifically the
+// CSE portion.
+ConceptSpecializationExpr *
+TemplateParameterListBuilder::constructConceptSpecializationExpr(
+    Sema &S, ConceptDecl *CD) {
+  ASTContext &Context = S.getASTContext();
+  SourceLocation Loc = Builder.Record->getBeginLoc();
+  DeclarationNameInfo DNI(CD->getDeclName(), Loc);
+  NestedNameSpecifierLoc NNSLoc;
+  DeclContext *DC = Builder.Record->getDeclContext();
+  TemplateArgumentListInfo TALI(Loc, Loc);
+
+  // Assume that the concept decl has just one template parameter
+  // This parameter should have been added when CD was constructed
+  // in getTypedBufferConceptDecl
+  assert(CD->getTemplateParameters()->size() == 1 &&
+         "unexpected concept decl parameter count");
+  TemplateTypeParmDecl *ConceptTTPD =
+      dyn_cast<TemplateTypeParmDecl>(CD->getTemplateParameters()->getParam(0));
+
+  // this TemplateTypeParmDecl is the template for the resource, and is
+  // used to construct a template argumentthat will be used
+  // to construct the ImplicitConceptSpecializationDecl
+  TemplateTypeParmDecl *T = TemplateTypeParmDecl::Create(
+      Context,                          // AST context
+      Builder.Record->getDeclContext(), // DeclContext
+      SourceLocation(), SourceLocation(),
+      /*D=*/0,                    // Depth in the template parameter list
+      /*P=*/0,                    // Position in the template parameter list
+      /*Id=*/nullptr,             // Identifier for 'T'
+      /*Typename=*/true,          // Indicates this is a 'typename' or 'class'
+      /*ParameterPack=*/false,    // Not a parameter pack
+      /*HasTypeConstraint=*/false // Has no type constraint
+  );
+
+  T->setDeclContext(DC);
+
+  QualType ConceptTType = Context.getTypeDeclType(ConceptTTPD);
+
+  // this is the 2nd template argument node, on which
+  // the concept constraint is actually being applied: 'element_type'
+  TemplateArgument ConceptTA = TemplateArgument(ConceptTType);
+
+  QualType CSETType = Context.getTypeDeclType(T);
+
+  // this is the 1st template argument node, which represents
+  // the abstract type that a concept would refer to: 'T'
+  TemplateArgument CSETA = TemplateArgument(CSETType);
+
+  ImplicitConceptSpecializationDecl *ImplicitCSEDecl =
+      ImplicitConceptSpecializationDecl::Create(
+          Context, Builder.Record->getDeclContext(), Loc, {CSETA});
+
+  // Constraint satisfaction is used to construct the
+  // ConceptSpecailizationExpr, and represents the 2nd Template Argument,
+  // located at the bottom of the sample AST above.
+  const ConstraintSatisfaction CS(CD, {ConceptTA});
+  TemplateArgumentLoc TAL =
+      S.getTrivialTemplateArgumentLoc(ConceptTA, QualType(), SourceLocation());
+
+  TALI.addArgument(TAL);
+  const ASTTemplateArgumentListInfo *ATALI =
+      ASTTemplateArgumentListInfo::Create(Context, TALI);
+
+  // In the concept reference, ATALI is what adds the extra
+  // TemplateArgument node underneath CSE
+  ConceptReference *CR =
+      ConceptReference::Create(Context, NNSLoc, Loc, DNI, CD, CD, ATALI);
+
+  ConceptSpecializationExpr *CSE =
+      ConceptSpecializationExpr::Create(Context, CR, ImplicitCSEDecl, &CS);
+
+  return CSE;
+}
+
+BuiltinTypeDeclBuilder &
+TemplateParameterListBuilder::finalizeTemplateArgs(ConceptDecl *CD) {
+  if (Params.empty())
+    return Builder;
+
+  ASTContext &AST = Builder.SemaRef.Context;
+  ConceptSpecializationExpr *CSE =
+      CD ? constructConceptSpecializationExpr(Builder.SemaRef, CD) : nullptr;
+  auto *ParamList = TemplateParameterList::Create(
+      AST, SourceLocation(), SourceLocation(), Params, SourceLocation(), CSE);
+  Builder.Template = ClassTemplateDecl::Create(
+      AST, Builder.Record->getDeclContext(), SourceLocation(),
+      DeclarationName(Builder.Record->getIdentifier()), ParamList,
+      Builder.Record);
+
+  Builder.Record->setDescribedClassTemplate(Builder.Template);
+  Builder.Template->setImplicit(true);
+  Builder.Template->setLexicalDeclContext(Builder.Record->getDeclContext());
+
+  // NOTE: setPreviousDecl before addDecl so new decl replace old decl when
+  // make visible.
+  Builder.Template->setPreviousDecl(Builder.PrevTemplate);
+  Builder.Record->getDeclContext()->addDecl(Builder.Template);
+  Params.clear();
+
+  QualType T = Builder.Template->getInjectedClassNameSpecialization();
+  T = AST.getInjectedClassNameType(Builder.Record, T);
+
+  return Builder;
+}
+
+Expr *BuiltinTypeMethodBuilder::convertPlaceholder(PlaceHolder PH) {
+  if (PH == PlaceHolder::Handle)
+    return getResourceHandleExpr();
+
+  if (PH == PlaceHolder::LastStmt) {
+    assert(!StmtsList.empty() && "no statements in the list");
+    Stmt *LastStmt = StmtsList.pop_back_val();
+    assert(isa<ValueStmt>(LastStmt) && "last statement does not have a value");
+    return cast<ValueStmt>(LastStmt)->getExprStmt();
+  }
+
+  ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
+  ParmVarDecl *ParamDecl = Method->getParamDecl(static_cast<unsigned>(PH));
+  return DeclRefExpr::Create(
+      AST, NestedNameSpecifierLoc(), SourceLocation(), ParamDecl, false,
+      DeclarationNameInfo(ParamDecl->getDeclName(), SourceLocation()),
+      ParamDecl->getType(), VK_PRValue);
+}
+
+BuiltinTypeMethodBuilder::BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB,
+                                                   StringRef Name,
+                                                   QualType ReturnTy,
+                                                   bool IsConst)
+    : DeclBuilder(DB), ReturnTy(ReturnTy), Method(nullptr), IsConst(IsConst) {
+  const IdentifierInfo &II =
+      DB.SemaRef.getASTContext().Idents.get(Name, tok::TokenKind::identifier);
+  NameInfo = DeclarationNameInfo(DeclarationName(&II), SourceLocation());
+}
+
+BuiltinTypeMethodBuilder &
+BuiltinTypeMethodBuilder::addParam(StringRef Name, QualType Ty,
+                                   HLSLParamModifierAttr::Spelling Modifier) {
+  assert(Method == nullptr && "Cannot add param, method already created");
+  const IdentifierInfo &II = DeclBuilder.SemaRef.getASTContext().Idents.get(
+      Name, tok::TokenKind::identifier);
+  Params.emplace_back(II, Ty, Modifier);
+  return *this;
+}
+
+void BuiltinTypeMethodBuilder::createMethodDecl() {
+  assert(Method == nullptr && "Method already created");
+
+  // create method type
+  ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
+  SmallVector<QualType> ParamTypes;
+  for (MethodParam &MP : Params)
+    ParamTypes.emplace_back(MP.Ty);
+
+  FunctionProtoType::ExtProtoInfo ExtInfo;
+  if (IsConst)
+    ExtInfo.TypeQuals.addConst();
+
+  QualType MethodTy = AST.getFunctionType(ReturnTy, ParamTypes, ExtInfo);
+
+  // create method decl
+  auto *TSInfo = AST.getTrivialTypeSourceInfo(MethodTy, SourceLocation());
+  Method = CXXMethodDecl::Create(
+      AST, DeclBuilder.Record, SourceLocation(), NameInfo, MethodTy, TSInfo,
+      SC_None, false, false, ConstexprSpecKind::Unspecified, SourceLocation());
+
+  // create params & set them to the function prototype
+  SmallVector<ParmVarDecl *> ParmDecls;
+  auto FnProtoLoc =
+      Method->getTypeSourceInfo()->getTypeLoc().getAs<FunctionProtoTypeLoc>();
+  for (int I = 0, E = Params.size(); I != E; I++) {
+    MethodParam &MP = Params[I];
+    ParmVarDecl *Parm = ParmVarDecl::Create(
+        AST, Method->getDeclContext(), SourceLocation(), SourceLocation(),
+        &MP.NameII, MP.Ty,
+        AST.getTrivialTypeSourceInfo(MP.Ty, SourceLocation()), SC_None,
+        nullptr);
+    if (MP.Modifier != HLSLParamModifierAttr::Keyword_in) {
+      auto *Mod =
+          HLSLParamModifierAttr::Create(AST, SourceRange(), MP.Modifier);
+      Parm->addAttr(Mod);
+    }
+    ParmDecls.push_back(Parm);
+    FnProtoLoc.setParam(I, Parm);
+  }
+  Method->setParams({ParmDecls});
+}
+
+Expr *BuiltinTypeMethodBuilder::getResourceHandleExpr() {
+  // The first statement added to a method or access to 'this' creates the
+  // declaration.
+  if (!Method)
+    createMethodDecl();
+
+  ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
+  CXXThisExpr *This = CXXThisExpr::Create(
+      AST, SourceLocation(), Method->getFunctionObjectParameterType(), true);
+  FieldDecl *HandleField = DeclBuilder.getResourceHandleField();
+  return MemberExpr::CreateImplicit(AST, This, false, HandleField,
+                                    HandleField->getType(), VK_LValue,
+                                    OK_Ordinary);
+}
+
+template <typename... Ts>
+BuiltinTypeMethodBuilder &
+BuiltinTypeMethodBuilder::callBuiltin(StringRef BuiltinName,
+                                      QualType ReturnType, Ts... ArgSpecs) {
+  std::array<Expr *, sizeof...(ArgSpecs)> Args{
+      convertPlaceholder(std::forward<Ts>(ArgSpecs))...};
+
+  // The first statement added to a method or access to 'this` creates the
+  // declaration.
+  if (!Method)
+    createMethodDecl();
+
+  ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
+  FunctionDecl *FD = lookupBuiltinFunction(DeclBuilder.SemaRef, BuiltinName);
+  DeclRefExpr *DRE = DeclRefExpr::Create(
+      AST, NestedNameSpecifierLoc(), SourceLocation(), FD, false,
+      FD->getNameInfo(), AST.BuiltinFnTy, VK_PRValue);
+
+  if (ReturnType.isNull())
+    ReturnType = FD->getReturnType();
+
+  Expr *Call = CallExpr::Create(AST, DRE, Args, ReturnType, VK_PRValue,
+                                SourceLocation(), FPOptionsOverride());
+  StmtsList.push_back(Call);
+  return *this;
+}
+
+template <typename TLHS, typename TRHS>
+BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::assign(TLHS LHS, TRHS RHS) 
{
+  Expr *LHSExpr = convertPlaceholder(LHS);
+  Expr *RHSExpr = convertPlaceholder(RHS);
+  Stmt *AssignStmt = BinaryOperator::Create(
+      DeclBuilder.SemaRef.getASTContext(), LHSExpr, RHSExpr, BO_Assign,
+      LHSExpr->getType(), ExprValueKind::VK_PRValue,
+      ExprObjectKind::OK_Ordinary, SourceLocation(), FPOptionsOverride());
+  StmtsList.push_back(AssignStmt);
+  return *this;
+}
+
+template <typename T>
+BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::dereference(T Ptr) {
+  Expr *PtrExpr = convertPlaceholder(Ptr);
+  Expr *Deref =
+      UnaryOperator::Create(DeclBuilder.SemaRef.getASTContext(), PtrExpr,
+                            UO_Deref, PtrExpr->getType()->getPointeeType(),
+                            VK_PRValue, OK_Ordinary, SourceLocation(),
+                            /*CanOverflow=*/false, FPOp...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/131032
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to