llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Ambrose Leeb (Sirraide)

<details>
<summary>Changes</summary>

This patch adds a helper function to `APValue` that walks the value recursively 
and visits all nested values. This functionality is currently used by 
`LinkageComputer::getLVForValue()` and it looks like I will be needing it for a 
patch soon.

Assisted-by: Codex

---
Full diff: https://github.com/llvm/llvm-project/pull/230243.diff


4 Files Affected:

- (modified) clang/include/clang/AST/APValue.h (+6) 
- (modified) clang/lib/AST/APValue.cpp (+111-91) 
- (added) clang/unittests/AST/APValueTest.cpp (+73) 
- (modified) clang/unittests/AST/CMakeLists.txt (+1) 


``````````diff
diff --git a/clang/include/clang/AST/APValue.h 
b/clang/include/clang/AST/APValue.h
index 35576a4b6403e9..571eaa146f56ae 100644
--- a/clang/include/clang/AST/APValue.h
+++ b/clang/include/clang/AST/APValue.h
@@ -22,6 +22,7 @@
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/PointerIntPair.h"
 #include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/STLFunctionalExtras.h"
 #include "llvm/ADT/bit.h"
 #include "llvm/Support/AlignOf.h"
 #include "llvm/Support/Compiler.h"
@@ -535,6 +536,11 @@ class LLVM_ATTRIBUTE_WARN_UNUSED APValue {
 
   ValueKind getKind() const { return Kind; }
 
+  /// Visit this value and every recursively nested value.
+  ///
+  /// Visitation stops if \p Visitor returns false.
+  void visit(llvm::function_ref<bool(const APValue &)> Visitor) const;
+
   bool isAbsent() const { return Kind == None; }
   bool isIndeterminate() const { return Kind == Indeterminate; }
   bool hasValue() const { return Kind != None && Kind != Indeterminate; }
diff --git a/clang/lib/AST/APValue.cpp b/clang/lib/AST/APValue.cpp
index 479c3c0d628963..97023be49c715b 100644
--- a/clang/lib/AST/APValue.cpp
+++ b/clang/lib/AST/APValue.cpp
@@ -21,6 +21,67 @@
 #include "llvm/Support/raw_ostream.h"
 using namespace clang;
 
+static bool visitAPValue(const APValue &Value,
+                         llvm::function_ref<bool(const APValue &)> Visitor) {
+  if (!Visitor(Value))
+    return false;
+
+  switch (Value.getKind()) {
+  case APValue::None:
+  case APValue::Indeterminate:
+  case APValue::Int:
+  case APValue::Float:
+  case APValue::FixedPoint:
+  case APValue::ComplexInt:
+  case APValue::ComplexFloat:
+  case APValue::LValue:
+  case APValue::MemberPointer:
+  case APValue::AddrLabelDiff:
+  case APValue::Reflection:
+    return true;
+
+  case APValue::Vector:
+    for (unsigned I = 0, N = Value.getVectorLength(); I != N; ++I)
+      if (!visitAPValue(Value.getVectorElt(I), Visitor))
+        return false;
+    return true;
+
+  case APValue::Matrix:
+    for (unsigned I = 0, N = Value.getMatrixNumElements(); I != N; ++I)
+      if (!visitAPValue(Value.getMatrixElt(I), Visitor))
+        return false;
+    return true;
+
+  case APValue::Array:
+    for (unsigned I = 0, N = Value.getArrayInitializedElts(); I != N; ++I)
+      if (!visitAPValue(Value.getArrayInitializedElt(I), Visitor))
+        return false;
+    return !Value.hasArrayFiller() ||
+           visitAPValue(Value.getArrayFiller(), Visitor);
+
+  case APValue::Struct:
+    for (unsigned I = 0, N = Value.getStructNumBases(); I != N; ++I)
+      if (!visitAPValue(Value.getStructBase(I), Visitor))
+        return false;
+    for (unsigned I = 0, N = Value.getStructNumFields(); I != N; ++I)
+      if (!visitAPValue(Value.getStructField(I), Visitor))
+        return false;
+    for (unsigned I = 0, N = Value.getStructNumVirtualBases(); I != N; ++I)
+      if (!visitAPValue(Value.getStructVirtualBase(I), Visitor))
+        return false;
+    return true;
+
+  case APValue::Union:
+    return !Value.getUnionField() ||
+           visitAPValue(Value.getUnionValue(), Visitor);
+  }
+  llvm_unreachable("unknown APValue kind");
+}
+
+void APValue::visit(llvm::function_ref<bool(const APValue &)> Visitor) const {
+  visitAPValue(*this, Visitor);
+}
+
 /// The identity of a type_info object depends on the canonical unqualified
 /// type only.
 TypeInfoLValue::TypeInfoLValue(const Type *T)
@@ -1204,99 +1265,58 @@ LinkageInfo LinkageComputer::getLVForValue(const 
APValue &V,
                                            LVComputationKind computation) {
   LinkageInfo LV = LinkageInfo::external();
 
-  auto MergeLV = [&](LinkageInfo MergeLV) {
-    LV.merge(MergeLV);
-    return LV.getLinkage() == Linkage::Internal;
-  };
-  auto Merge = [&](const APValue &V) {
-    return MergeLV(getLVForValue(V, computation));
-  };
-
-  switch (V.getKind()) {
-  case APValue::None:
-  case APValue::Indeterminate:
-  case APValue::Int:
-  case APValue::Float:
-  case APValue::FixedPoint:
-  case APValue::ComplexInt:
-  case APValue::ComplexFloat:
-  case APValue::Vector:
-  case APValue::Reflection:
-  case APValue::Matrix:
-    break;
-
-  case APValue::AddrLabelDiff:
-    // Even for an inline function, it's not reasonable to treat a difference
-    // between the addresses of labels as an external value.
-    return LinkageInfo::internal();
-
-  case APValue::Struct: {
-    for (unsigned I = 0, N = V.getStructNumBases(); I != N; ++I)
-      if (Merge(V.getStructBase(I)))
-        break;
-    for (unsigned I = 0, N = V.getStructNumFields(); I != N; ++I)
-      if (Merge(V.getStructField(I)))
-        break;
-    for (unsigned I = 0, N = V.getStructNumVirtualBases(); I != N; ++I)
-      if (Merge(V.getStructVirtualBase(I)))
-        break;
-    break;
-  }
-
-  case APValue::Union:
-    if (V.getUnionField())
-      Merge(V.getUnionValue());
-    break;
-
-  case APValue::Array: {
-    for (unsigned I = 0, N = V.getArrayInitializedElts(); I != N; ++I)
-      if (Merge(V.getArrayInitializedElt(I)))
-        break;
-    if (V.hasArrayFiller())
-      Merge(V.getArrayFiller());
-    break;
-  }
+  auto MergeLV = [&](LinkageInfo MergeLV) { LV.merge(MergeLV); };
+  V.visit([&](const APValue &Value) {
+    switch (Value.getKind()) {
+    case APValue::AddrLabelDiff:
+      // Even for an inline function, it's not reasonable to treat a difference
+      // between the addresses of labels as an external value.
+      LV = LinkageInfo::internal();
+      return false;
 
-  case APValue::LValue: {
-    if (!V.getLValueBase()) {
-      // Null or absolute address: this is external.
-    } else if (const auto *VD =
-                   V.getLValueBase().dyn_cast<const ValueDecl *>()) {
-      if (VD && MergeLV(getLVForDecl(VD, computation)))
-        break;
-    } else if (const auto TI = V.getLValueBase().dyn_cast<TypeInfoLValue>()) {
-      if (MergeLV(getLVForType(*TI.getType(), computation)))
-        break;
-    } else if (const Expr *E = V.getLValueBase().dyn_cast<const Expr *>()) {
-      // Almost all expression bases are internal. The exception is
-      // lifetime-extended temporaries.
-      // FIXME: These should be modeled as having the
-      // LifetimeExtendedTemporaryDecl itself as the base.
-      // FIXME: If we permit Objective-C object literals in template arguments,
-      // they should not imply internal linkage.
-      auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E);
-      if (!MTE || MTE->getStorageDuration() == SD_FullExpression)
-        return LinkageInfo::internal();
-      if (MergeLV(getLVForDecl(MTE->getExtendingDecl(), computation)))
-        break;
-    } else {
-      assert(V.getLValueBase().is<DynamicAllocLValue>() &&
-             "unexpected LValueBase kind");
-      return LinkageInfo::internal();
+    case APValue::LValue:
+      if (!Value.getLValueBase()) {
+        // Null or absolute address: this is external.
+      } else if (const auto *VD =
+                     Value.getLValueBase().dyn_cast<const ValueDecl *>()) {
+        MergeLV(getLVForDecl(VD, computation));
+      } else if (const auto TI =
+                     Value.getLValueBase().dyn_cast<TypeInfoLValue>()) {
+        MergeLV(getLVForType(*TI.getType(), computation));
+      } else if (const Expr *E =
+                     Value.getLValueBase().dyn_cast<const Expr *>()) {
+        // Almost all expression bases are internal. The exception is
+        // lifetime-extended temporaries.
+        // FIXME: These should be modeled as having the
+        // LifetimeExtendedTemporaryDecl itself as the base.
+        // FIXME: If we permit Objective-C object literals in template
+        // arguments, they should not imply internal linkage.
+        auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E);
+        if (!MTE || MTE->getStorageDuration() == SD_FullExpression)
+          LV = LinkageInfo::internal();
+        else
+          MergeLV(getLVForDecl(MTE->getExtendingDecl(), computation));
+      } else {
+        assert(Value.getLValueBase().is<DynamicAllocLValue>() &&
+               "unexpected LValueBase kind");
+        LV = LinkageInfo::internal();
+      }
+      // The lvalue path doesn't matter: pointers to all subobjects always have
+      // the same visibility as pointers to the complete object.
+      return LV.getLinkage() != Linkage::Internal;
+
+    case APValue::MemberPointer:
+      if (const NamedDecl *D = Value.getMemberPointerDecl())
+        MergeLV(getLVForDecl(D, computation));
+      // Note that we could have a base-to-derived conversion here to a member
+      // of a derived class with less linkage/visibility. That's covered by the
+      // linkage and visibility of the value's type.
+      return LV.getLinkage() != Linkage::Internal;
+
+    default:
+      return true;
     }
-    // The lvalue path doesn't matter: pointers to all subobjects always have
-    // the same visibility as pointers to the complete object.
-    break;
-  }
-
-  case APValue::MemberPointer:
-    if (const NamedDecl *D = V.getMemberPointerDecl())
-      MergeLV(getLVForDecl(D, computation));
-    // Note that we could have a base-to-derived conversion here to a member of
-    // a derived class with less linkage/visibility. That's covered by the
-    // linkage and visibility of the value's type.
-    break;
-  }
+  });
 
   return LV;
 }
diff --git a/clang/unittests/AST/APValueTest.cpp 
b/clang/unittests/AST/APValueTest.cpp
new file mode 100644
index 00000000000000..726fca8e5c9aa5
--- /dev/null
+++ b/clang/unittests/AST/APValueTest.cpp
@@ -0,0 +1,73 @@
+//===- unittests/AST/APValueTest.cpp - APValue tests 
----------------------===//
+//
+// 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/AST/APValue.h"
+#include "llvm/ADT/DenseMap.h"
+#include "gtest/gtest.h"
+#include <cstdint>
+#include <utility>
+
+using namespace clang;
+
+namespace {
+
+static APValue makeInt(uint64_t Value) {
+  return APValue(llvm::APSInt(llvm::APInt(32, Value), /*IsUnsigned=*/false));
+}
+
+static APValue makeNestedValue() {
+  APValue VectorElements[] = {makeInt(1), makeInt(2)};
+  APValue Vector(VectorElements, 2);
+
+  APValue MatrixElements[] = {makeInt(3), makeInt(4), makeInt(5), makeInt(6)};
+  APValue Matrix(MatrixElements, 2, 2);
+
+  APValue Base(APValue::UninitStruct(), 0, 2);
+  Base.getStructField(0) = std::move(Vector);
+  Base.getStructField(1) = std::move(Matrix);
+
+  APValue Array(APValue::UninitArray(), 1, 2);
+  Array.getArrayInitializedElt(0) = makeInt(7);
+  Array.getArrayFiller() = makeInt(0);
+
+  APValue Union(static_cast<const FieldDecl *>(nullptr));
+  APValue VirtualBase(APValue::UninitStruct(), 0, 1);
+  VirtualBase.getStructField(0) = std::move(Union);
+
+  APValue Result(APValue::UninitStruct(), 1, 1, 1);
+  Result.getStructBase(0) = std::move(Base);
+  Result.getStructField(0) = std::move(Array);
+  Result.getStructVirtualBase(0) = std::move(VirtualBase);
+  return Result;
+}
+
+TEST(APValueTest, VisitCountsNestedValueKinds) {
+  APValue Value = makeNestedValue();
+  llvm::DenseMap<APValue::ValueKind, unsigned> Counts;
+  Value.visit([&](const APValue &SubValue) {
+    ++Counts[SubValue.getKind()];
+    return true;
+  });
+
+  const llvm::DenseMap<APValue::ValueKind, unsigned> Expected = {
+      {APValue::Int, 8},   {APValue::Vector, 1}, {APValue::Matrix, 1},
+      {APValue::Array, 1}, {APValue::Struct, 3}, {APValue::Union, 1},
+  };
+  EXPECT_EQ(Counts, Expected);
+}
+
+TEST(APValueTest, VisitStopsWhenCallbackReturnsFalse) {
+  APValue Value = makeNestedValue();
+  for (unsigned StopAfter : {1u, 2u, 5u}) {
+    unsigned NumVisited = 0;
+    Value.visit([&](const APValue &) { return ++NumVisited < StopAfter; });
+    EXPECT_EQ(NumVisited, StopAfter);
+  }
+}
+
+} // namespace
diff --git a/clang/unittests/AST/CMakeLists.txt 
b/clang/unittests/AST/CMakeLists.txt
index e726cc3299a5a5..8e4cb5af59c923 100644
--- a/clang/unittests/AST/CMakeLists.txt
+++ b/clang/unittests/AST/CMakeLists.txt
@@ -1,6 +1,7 @@
 add_subdirectory(ByteCode)
 
 add_clang_unittest(ASTTests
+  APValueTest.cpp
   ASTContextParentMapTest.cpp
   ASTDumperTest.cpp
   StringLiteral.cpp

``````````

</details>


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

Reply via email to