[llvm-branch-commits] [clang] [NFC][SSAF][UnsafeBufferUsage] Separate EntityPointerLevel and UnsafeBufferUsage (PR #188648)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Wed Mar 25 17:54:22 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-ssaf
Author: Ziqing Luo (ziqingluo-90)
<details>
<summary>Changes</summary>
EntityPointerLevel as a common data structure will later be shared by UnsafeBufferUsage and pointer assignments analysis. So this commit makes them separate:
- EntityPointerLevel provides the data structure and translation
- UnsafeBufferUsage uses EntityPointerLevel to translate unsafe pointers to EPLs.
---
Patch is 40.49 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/188648.diff
8 Files Affected:
- (added) clang/include/clang/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel.h (+134)
- (modified) clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h (+3-70)
- (modified) clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.h (-5)
- (modified) clang/lib/ScalableStaticAnalysisFramework/Analyses/CMakeLists.txt (+2-1)
- (added) clang/lib/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel.cpp (+332)
- (modified) clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.cpp (+25-30)
- (modified) clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.cpp (+9-216)
- (modified) clang/unittests/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp (+1-3)
``````````diff
diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel.h b/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel.h
new file mode 100644
index 0000000000000..f2a2c73a29a7a
--- /dev/null
+++ b/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel.h
@@ -0,0 +1,134 @@
+//===---------------- EntityPointerLevel.h ----------------*- 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 LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_ANALYSES_ENTITYPOINTERLEVEL_H
+#define LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_ANALYSES_ENTITYPOINTERLEVEL_H
+
+#include "clang/AST/Decl.h"
+#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityId.h"
+#include "clang/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat.h"
+#include <set>
+
+namespace clang::ssaf {
+
+/// An EntityPointerLevel is associated with a level of the declared
+/// pointer/array type of an entity. In the fully-expanded spelling of the
+/// declared type, a EntityPointerLevel is associated with a '*' (or a '[]`) in
+/// that declaration.
+///
+/// For example, for 'int *p[10];', there are two EntityPointerLevels. One
+/// is associated with 'int *[10]' of 'p' and the other is associated with 'int
+/// *' of 'p'.
+///
+/// An EntityPointerLevel can be identified by an EntityId and an unsigned
+/// integer indicating the pointer level: '(EntityId, PointerLevel)'.
+/// An EntityPointerLevel 'P' is valid iff 'P.EntityId' has a pointer type with
+/// at least 'P.PointerLevel' levels (This implies 'P.PointerLevel > 0').
+///
+/// For the same example 'int *p[10];', the EntityPointerLevels below are valid:
+/// - '(p, 2)' is associated with the 'int *' part of the declared type of 'p';
+/// - '(p, 1)' is associated with the 'int *[10]' part of the declared type of
+/// 'p'.
+class EntityPointerLevel {
+ EntityId Entity;
+ unsigned PointerLevel;
+
+ friend class EntityPointerLevelTranslator;
+ friend llvm::Expected<EntityPointerLevel>
+ entityPointerLevelFromJSON(const llvm::json::Value &EPLData,
+ JSONFormat::EntityIdFromJSONFn EntityIdFromJSON);
+ // For unittests:
+ friend EntityPointerLevel buildEntityPointerLevel(EntityId, unsigned);
+
+ // EntityPointerLevel(EntityId Entity, unsigned PointerLevel)
+ // : Entity(Entity), PointerLevel(PointerLevel) {}
+ EntityPointerLevel(std::pair<EntityId, unsigned> Pair)
+ : Entity(Pair.first), PointerLevel(Pair.second) {}
+
+public:
+ EntityId getEntity() const { return Entity; }
+ unsigned getPointerLevel() const { return PointerLevel; }
+
+ bool operator==(const EntityPointerLevel &Other) const {
+ return std::tie(Entity, PointerLevel) ==
+ std::tie(Other.Entity, Other.PointerLevel);
+ }
+
+ bool operator!=(const EntityPointerLevel &Other) const {
+ return !(*this == Other);
+ }
+
+ bool operator<(const EntityPointerLevel &Other) const {
+ return std::tie(Entity, PointerLevel) <
+ std::tie(Other.Entity, Other.PointerLevel);
+ }
+
+ /// Compares `EntityPointerLevel`s; additionally, partially compares
+ /// `EntityPointerLevel` with `EntityId`.
+ struct Comparator {
+ using is_transparent = void;
+ bool operator()(const EntityPointerLevel &L,
+ const EntityPointerLevel &R) const {
+ return L < R;
+ }
+ bool operator()(const EntityId &L, const EntityPointerLevel &R) const {
+ return L < R.getEntity();
+ }
+ bool operator()(const EntityPointerLevel &L, const EntityId &R) const {
+ return L.getEntity() < R;
+ }
+ };
+};
+
+using EntityPointerLevelSet =
+ std::set<EntityPointerLevel, EntityPointerLevel::Comparator>;
+
+/// Translate a pointer/array type expression 'E' to a (set of)
+/// EntityPointerLevel(s) associated with the declared type of the base address
+/// of `E`. If the base address of `E` is not associated with an entity, the
+/// translation result is an empty set.
+///
+/// \param E the pointer expression to be translated
+/// \param Ctx the AST context of `E`
+/// \param AddEntity the callback provided by the caller to convert EntityNames
+/// to EntityIds.
+llvm::Expected<EntityPointerLevelSet>
+translateEntityPointerLevel(const Expr *E, ASTContext &Ctx,
+ std::function<EntityId(EntityName EN)> AddEntity);
+
+/// Create an EntityPointerLevel (EPL) from a NamedDecl of a pointer/array type.
+///
+/// \param E the pointer expression to be translated
+/// \param Ctx the AST context of `E`
+/// \param AddEntity the callback provided by the caller to convert EntityNames
+/// to EntityIds.
+/// \param IsFunRet true iff the created EPL is associated with the return type
+/// of a function entity.
+llvm::Expected<EntityPointerLevel>
+creatEntityPointerLevel(const NamedDecl *ND, ASTContext &Ctx,
+ std::function<EntityId(EntityName EN)> AddEntity,
+ bool IsFunRet = false);
+
+/// Creates a new EntityPointerLevel (EPL) from `E` by incrementing `E`'s
+/// pointer level.
+/// \return the EPL that is associated with the pointee (or array element) type
+/// of `E`'s associated pointer/array tyoe of the same entity.
+EntityPointerLevel incrementPointerLevel(const EntityPointerLevel &E);
+
+llvm::json::Value
+entityPointerLevelToJSON(const EntityPointerLevel &EPL,
+ JSONFormat::EntityIdToJSONFn EntityId2JSON);
+
+llvm::Expected<EntityPointerLevel>
+entityPointerLevelFromJSON(const llvm::json::Value &EPLData,
+ JSONFormat::EntityIdFromJSONFn EntityIdFromJSON);
+
+/// Proxy function creating EPLs for unit tests:
+EntityPointerLevel buildEntityPointerLevel(EntityId, unsigned);
+} // namespace clang::ssaf
+#endif // LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_ANALYSES_ENTITYPOINTERLEVEL_H
diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h b/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h
index 2b36c47fe67a5..0b9a4170f653d 100644
--- a/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h
+++ b/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h
@@ -9,81 +9,14 @@
#ifndef LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_ANALYSES_UNSAFEBUFFERUSAGE_UNSAFEBUFFERUSAGE_H
#define LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_ANALYSES_UNSAFEBUFFERUSAGE_UNSAFEBUFFERUSAGE_H
-#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityId.h"
+#include "clang/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel.h"
#include "clang/ScalableStaticAnalysisFramework/Core/Model/SummaryName.h"
#include "clang/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat.h"
#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/EntitySummary.h"
-#include <set>
namespace clang::ssaf {
-
-/// An EntityPointerLevel represents a level of the declared pointer/array
-/// type of an entity. In the fully-expanded spelling of the declared type, a
-/// EntityPointerLevel is associated with a '*' (or a '[]`) in that declaration.
-///
-/// For example, for 'int *p[10];', there are two EntityPointerLevels. One
-/// is associated with 'int *[10]' of 'p' and the other is associated with 'int
-/// *' of 'p'.
-///
-/// An EntityPointerLevel can be identified by an EntityId and an unsigned
-/// integer indicating the pointer level: '(EntityId, PointerLevel)'.
-/// An EntityPointerLevel 'P' is valid iff 'P.EntityId' has a pointer type with
-/// at least 'P.PointerLevel' levels (This implies 'P.PointerLevel > 0').
-///
-/// For the same example 'int *p[10];', the EntityPointerLevels below are valid:
-/// - '(p, 2)' is associated with the 'int *' part of the declared type of 'p';
-/// - '(p, 1)' is associated with the 'int *[10]' part of the declared type of
-/// 'p'.
-class EntityPointerLevel {
- EntityId Entity;
- unsigned PointerLevel;
-
- friend class UnsafeBufferUsageTUSummaryExtractor;
- friend class UnsafeBufferUsageEntitySummary;
-
- EntityPointerLevel(EntityId Entity, unsigned PointerLevel)
- : Entity(Entity), PointerLevel(PointerLevel) {}
-
-public:
- EntityId getEntity() const { return Entity; }
- unsigned getPointerLevel() const { return PointerLevel; }
-
- bool operator==(const EntityPointerLevel &Other) const {
- return std::tie(Entity, PointerLevel) ==
- std::tie(Other.Entity, Other.PointerLevel);
- }
-
- bool operator!=(const EntityPointerLevel &Other) const {
- return !(*this == Other);
- }
-
- bool operator<(const EntityPointerLevel &Other) const {
- return std::tie(Entity, PointerLevel) <
- std::tie(Other.Entity, Other.PointerLevel);
- }
-
- /// Compares `EntityPointerLevel`s; additionally, partially compares
- /// `EntityPointerLevel` with `EntityId`.
- struct Comparator {
- using is_transparent = void;
- bool operator()(const EntityPointerLevel &L,
- const EntityPointerLevel &R) const {
- return L < R;
- }
- bool operator()(const EntityId &L, const EntityPointerLevel &R) const {
- return L < R.getEntity();
- }
- bool operator()(const EntityPointerLevel &L, const EntityId &R) const {
- return L.getEntity() < R;
- }
- };
-};
-
-using EntityPointerLevelSet =
- std::set<EntityPointerLevel, EntityPointerLevel::Comparator>;
-
-/// An UnsafeBufferUsageEntitySummary is an immutable set of unsafe buffers, in
-/// the form of EntityPointerLevel.
+/// An UnsafeBufferUsageEntitySummary contains a set of EntityPointerLevels
+/// extracted from unsafe buffer pointers contributed by an entity.
class UnsafeBufferUsageEntitySummary final : public EntitySummary {
const EntityPointerLevelSet UnsafeBuffers;
diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.h b/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.h
index 765b2c37562ce..13d4e18b4e81f 100644
--- a/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.h
+++ b/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.h
@@ -22,11 +22,6 @@ class UnsafeBufferUsageTUSummaryExtractor : public TUSummaryExtractor {
UnsafeBufferUsageTUSummaryExtractor(TUSummaryBuilder &Builder)
: TUSummaryExtractor(Builder) {}
- static EntityPointerLevel buildEntityPointerLevel(EntityId Entity,
- unsigned PointerLevel) {
- return {Entity, PointerLevel};
- }
-
EntityId addEntity(EntityName EN) { return SummaryBuilder.addEntity(EN); }
std::unique_ptr<UnsafeBufferUsageEntitySummary>
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Analyses/CMakeLists.txt b/clang/lib/ScalableStaticAnalysisFramework/Analyses/CMakeLists.txt
index c85fa044c1e9f..c8544d073d276 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Analyses/CMakeLists.txt
+++ b/clang/lib/ScalableStaticAnalysisFramework/Analyses/CMakeLists.txt
@@ -3,8 +3,9 @@ set(LLVM_LINK_COMPONENTS
)
add_clang_library(clangScalableStaticAnalysisFrameworkAnalyses
+ EntityPointerLevel.cpp
UnsafeBufferUsage/UnsafeBufferUsage.cpp
- UnsafeBufferUsage/UnsafeBufferUsageExtractor.cpp
+ UnsafeBufferUsage/UnsafeBufferUsageExtractor.cpp
LINK_LIBS
clangAST
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel.cpp b/clang/lib/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel.cpp
new file mode 100644
index 0000000000000..e607529342351
--- /dev/null
+++ b/clang/lib/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel.cpp
@@ -0,0 +1,332 @@
+//===----------------- EntityPointerLevel.cpp -------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+#include "clang/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/ScalableStaticAnalysisFramework/Core/ASTEntityMapping.h"
+#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityName.h"
+#include <optional>
+
+namespace {
+using namespace clang;
+template <typename NodeTy, typename... Ts>
+static inline llvm::Error strErrAtNode(ASTContext &Ctx, const NodeTy &N,
+ StringRef Fmt, const Ts &...Args) {
+ std::string LocStr = N.getBeginLoc().printToString(Ctx.getSourceManager());
+ llvm::SmallVector<char> FmtData;
+
+ (Fmt + " at %s").toStringRef(FmtData);
+ return llvm::createStringError(FmtData.data(), Args..., LocStr.c_str());
+}
+
+static inline llvm::Error entityNameErrFor(ASTContext &Ctx,
+ const NamedDecl &D) {
+ return strErrAtNode(Ctx, D, "failed to create entity name for %s",
+ D.getNameAsString().data());
+}
+
+template <typename DeclOrExpr>
+static bool hasPtrOrArrType(const DeclOrExpr &E) {
+ return llvm::isa<PointerType>(E.getType().getCanonicalType()) ||
+ llvm::isa<ArrayType>(E.getType().getCanonicalType());
+}
+
+template <typename... Ts>
+static inline llvm::Error makeErrorSawButExpected(const llvm::json::Value &Saw,
+ llvm::StringRef Expected,
+ const Ts &...ExpectedArgs) {
+ return llvm::createStringError(
+ ("saw %s but expected " + Expected).str().c_str(),
+ llvm::formatv("{0:2}", Saw).str().data(), Expected.data(),
+ ExpectedArgs...);
+}
+} // namespace
+
+namespace clang::ssaf {
+// Translate a pointer type expression 'E' to a (set of) EntityPointerLevel(s)
+// associated with the declared type of the base address of `E`. If the base
+// address of `E` is not associated with an entity, the translation result is an
+// empty set.
+//
+// The translation is a process of traversing into the pointer 'E' until its
+// base address can be represented by an entity, with the number of dereferences
+// tracked by incrementing the pointer level. Naturally, taking address of, as
+// the inverse operation of dereference, is tracked by decrementing the pointer
+// level.
+//
+// For example, suppose there are pointers and arrays declared as
+// int *ptr, **p1, **p2;
+// int arr[10][10];
+// , the translation of expressions involving these base addresses will be:
+// Translate(ptr + 5) -> {(ptr, 1)}
+// Translate(arr[5]) -> {(arr, 2)}
+// Translate(cond ? p1[5] : p2) -> {(p1, 2), (p2, 1)}
+// Translate(&arr[5]) -> {(arr, 1)}
+class EntityPointerLevelTranslator
+ : public ConstStmtVisitor<EntityPointerLevelTranslator,
+ Expected<EntityPointerLevelSet>> {
+ friend class StmtVisitorBase;
+
+ // Fallback method for all unsupported expression kind:
+ llvm::Error fallback(const Stmt *E) {
+ return strErrAtNode(Ctx, *E,
+ "attempt to translate %s to EntityPointerLevels",
+ E->getStmtClassName());
+ }
+
+ EntityPointerLevel createEntityPointerLevelFor(const EntityName &Name) {
+ return EntityPointerLevel({AddEntity(Name), 1});
+ }
+
+ // The common helper function for Translate(*base):
+ // Translate(*base) -> Translate(base) with .pointerLevel + 1
+ Expected<EntityPointerLevelSet> translateDereferencePointer(const Expr *Ptr) {
+ assert(hasPtrOrArrType(*Ptr));
+
+ Expected<EntityPointerLevelSet> SubResult = Visit(Ptr);
+ if (!SubResult)
+ return SubResult.takeError();
+
+ auto Incremented = llvm::map_range(*SubResult, incrementPointerLevel);
+ return EntityPointerLevelSet{Incremented.begin(), Incremented.end()};
+ }
+
+ std::function<EntityId(EntityName EN)> AddEntity;
+ ASTContext &Ctx;
+
+public:
+ EntityPointerLevelTranslator(std::function<EntityId(EntityName EN)> AddEntity,
+ ASTContext &Ctx)
+ : AddEntity(AddEntity), Ctx(Ctx) {}
+
+ Expected<EntityPointerLevelSet> translate(const Expr *E) { return Visit(E); }
+ Expected<EntityPointerLevel> translate(const NamedDecl *D, bool IsRet) {
+ if (IsRet && !isa<FunctionDecl>(D))
+ return strErrAtNode(
+ Ctx, *D,
+ "attempt to call getEntityNameForReturn on a NamedDecl of %s kind",
+ D->getDeclKindName());
+
+ std::optional<EntityName> EN =
+ IsRet ? getEntityNameForReturn(cast<FunctionDecl>(D))
+ : getEntityName(D);
+ if (EN)
+ return createEntityPointerLevelFor(*EN);
+ return entityNameErrFor(Ctx, *D);
+ }
+
+ static EntityPointerLevel incrementPointerLevel(const EntityPointerLevel &E) {
+ return EntityPointerLevel({E.getEntity(), E.getPointerLevel() + 1});
+ }
+
+ static EntityPointerLevel decrementPointerLevel(const EntityPointerLevel &E) {
+ assert(E.getPointerLevel() > 0);
+ return EntityPointerLevel({E.getEntity(), E.getPointerLevel() - 1});
+ }
+
+private:
+ Expected<EntityPointerLevelSet> VisitStmt(const Stmt *E) {
+ return fallback(E);
+ }
+
+ // Translate(base + x) -> Translate(base)
+ // Translate(x + base) -> Translate(base)
+ // Translate(base - x) -> Translate(base)
+ // Translate(base {+=, -=, =} x) -> Translate(base)
+ // Translate(x, base) -> Translate(base)
+ Expected<EntityPointerLevelSet> VisitBinaryOperator(const BinaryOperator *E) {
+ switch (E->getOpcode()) {
+ case clang::BO_Add:
+ if (hasPtrOrArrType(*E->getLHS()))
+ return Visit(E->getLHS());
+ return Visit(E->getRHS());
+ case clang::BO_Sub:
+ case clang::BO_AddAssign:
+ case clang::BO_SubAssign:
+ case clang::BO_Assign:
+ return Visit(E->getLHS());
+ case clang::BO_Comma:
+ return Visit(E->getRHS());
+ default:
+ return fallback(E);
+ }
+ }
+
+ // Translate({++, --}base) -> Translate(base)
+ // Translate(base{++, --}) -> Translate(base)
+ // Translate(*base) -> Translate(base) with .pointerLevel += 1
+ // Translate(&base) -> {}, if Translate(base) is {}
+ // -> Translate(base) with .pointerLevel -= 1
+ Expected<EntityPointerLevelSet> VisitUnaryOperator(const UnaryOperator *E) {
+ switch (E->getOpcode()) {
+ case clang::UO_PostInc:
+ case clang::UO_PostDec:
+ case clang::UO_PreInc:
+ case clang::UO_PreDec:
+ return Visit(E->getSubExpr());
+ case clang::UO_AddrOf: {
+ Expected<EntityPointerLevelSet> SubResult = Visit(E->getSubExpr());
+ if (!SubResult)
+ return SubResult.takeError();
+
+ auto Decremented = llvm::map_range(*SubResult, decrementPointerLevel);
+ return EntityPointerLevelSet{Decremented.begin(), Decremented.end()};
+ }
+ case clang::UO_Deref:
+ return translateDereferencePointer(E->getSubExpr());
+ default:
+ return fallback(E);
+ }
+ }
+
+ // Translate((T*)base) -> Translate(p) if p has pointer type
+ // -> {} otherwise
+ Expected<EntityPointerLevelSet> VisitCastExpr(const CastExpr *E) {
+ if (hasPtrOrArrType(*E->getSubExpr()))
+ return Visit(E->getSubExpr());
+ return EntityPointerLevelSet{};
+ }
+
+ // Translate(f(...)) -> {} if it is an indirect call
+ // -> {(f_return, 1)}, otherwise
+ Expected<EntityPointerLevelSet> VisitCallExpr(const CallExpr *E) {
+ if (auto *FD = E->getDirectCallee())
+ if (auto FDEntityName = getEntityNameForReturn(FD))
+ return EntityPointerLevelSet{
+ createEntityPointerLevelFor(*FDEntityName)};
+ return EntityPointerLevelSet{};
+ }
+
+ // Translate(base[x]) -> Translate(*base)
+ Expected<EntityPointerLevelSet>
+ VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
+ return translateDereferencePointer(E->getBase());
+ }
+
+ // Translate(cond ? base1 : base2) := Tran...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/188648
More information about the llvm-branch-commits
mailing list