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
