[clang] 3214f7b - Revert "[clang][dataflow] Show triangle in `` element. (#67431)"
Author: Martin Braenne Date: 2023-09-28T09:07:20Z New Revision: 3214f7bf6c6f1218404584b6c36bd3d4033eb22d URL: https://github.com/llvm/llvm-project/commit/3214f7bf6c6f1218404584b6c36bd3d4033eb22d DIFF: https://github.com/llvm/llvm-project/commit/3214f7bf6c6f1218404584b6c36bd3d4033eb22d.diff LOG: Revert "[clang][dataflow] Show triangle in `` element. (#67431)" This reverts commit fb933fc6d76de854cb9eadf984f8900b9304d347. The commit broke buildbots due to non-ASCII characters in HTMLLogger.css. Added: Modified: clang/lib/Analysis/FlowSensitive/HTMLLogger.css clang/lib/Analysis/FlowSensitive/HTMLLogger.html Removed: diff --git a/clang/lib/Analysis/FlowSensitive/HTMLLogger.css b/clang/lib/Analysis/FlowSensitive/HTMLLogger.css index 9737d1416f22abe..0ac1902ea4651ec 100644 --- a/clang/lib/Analysis/FlowSensitive/HTMLLogger.css +++ b/clang/lib/Analysis/FlowSensitive/HTMLLogger.css @@ -123,21 +123,10 @@ code.line:has(.bb-select):before { font-size: x-small; flex-grow: 1; } -.value > summary { +.value summary { background-color: #ace; display: flex; - cursor: pointer; -} -.value > summary::before { - content: '►'; - margin-right: 0.5em; - font-size: 0.9em; -} -.value[open] > summary::before { - content: '▼'; -} -.value > summary > .location { - margin-left: auto; + justify-content: space-between; } .value .address { font-size: xx-small; diff --git a/clang/lib/Analysis/FlowSensitive/HTMLLogger.html b/clang/lib/Analysis/FlowSensitive/HTMLLogger.html index 6d866d57e144866..87695623cb318b2 100644 --- a/clang/lib/Analysis/FlowSensitive/HTMLLogger.html +++ b/clang/lib/Analysis/FlowSensitive/HTMLLogger.html @@ -18,7 +18,7 @@ #{{v.value_id}} -{{v.type}} @{{v.location}} +{{v.type}} @{{v.location}} https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 6236bf5 - [clang][dataflow] Strengthen flow condition assertions.
Author: Martin Braenne Date: 2023-07-18T13:41:43Z New Revision: 6236bf53418eb23c62a73d6346f0edec914084e7 URL: https://github.com/llvm/llvm-project/commit/6236bf53418eb23c62a73d6346f0edec914084e7 DIFF: https://github.com/llvm/llvm-project/commit/6236bf53418eb23c62a73d6346f0edec914084e7.diff LOG: [clang][dataflow] Strengthen flow condition assertions. Instead of asserting merely that the flow condition doesn't imply that a variable is true, make the stronger assertion that the flow condition implies that the variable is false. Reviewed By: ymandel, xazax.hun Differential Revision: https://reviews.llvm.org/D155067 Added: Modified: clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index e2800452ab6bdb..291f8329a60fde 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -3619,7 +3619,8 @@ TEST(TransferTest, BooleanEquality) { EXPECT_TRUE(EnvThen.flowConditionImplies(BarValThen)); auto &BarValElse = getFormula(*BarDecl, EnvElse); -EXPECT_FALSE(EnvElse.flowConditionImplies(BarValElse)); +EXPECT_TRUE( +EnvElse.flowConditionImplies(EnvElse.arena().makeNot(BarValElse))); }); } @@ -3650,7 +3651,8 @@ TEST(TransferTest, BooleanInequality) { ASSERT_THAT(BarDecl, NotNull()); auto &BarValThen = getFormula(*BarDecl, EnvThen); -EXPECT_FALSE(EnvThen.flowConditionImplies(BarValThen)); +EXPECT_TRUE( +EnvThen.flowConditionImplies(EnvThen.arena().makeNot(BarValThen))); auto &BarValElse = getFormula(*BarDecl, EnvElse); EXPECT_TRUE(EnvElse.flowConditionImplies(BarValElse)); ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 8b5d3ba - [clang][dataflow] Print the source line if we saw unexpected diagnostics in tests.
Author: Martin Braenne Date: 2023-07-20T12:40:22Z New Revision: 8b5d3ba829c162fd4890fd65a4629ce0715825ee URL: https://github.com/llvm/llvm-project/commit/8b5d3ba829c162fd4890fd65a4629ce0715825ee DIFF: https://github.com/llvm/llvm-project/commit/8b5d3ba829c162fd4890fd65a4629ce0715825ee.diff LOG: [clang][dataflow] Print the source line if we saw unexpected diagnostics in tests. This makes it easier to determine which line the unexpected happened on; previously, we would only get the line number. Reviewed By: ymandel Differential Revision: https://reviews.llvm.org/D155802 Added: Modified: clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp Removed: diff --git a/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp b/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp index 4bac015c995f68..a181f284370886 100644 --- a/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp @@ -12,6 +12,7 @@ #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Basic/SourceLocation.h" +#include "clang/Frontend/TextDiagnostic.h" #include "clang/Tooling/Tooling.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/STLExtras.h" @@ -1334,7 +1335,17 @@ class UncheckedOptionalAccessTest auto &SrcMgr = AO.ASTCtx.getSourceManager(); llvm::DenseSet DiagnosticLines; for (SourceLocation &Loc : Diagnostics) { -DiagnosticLines.insert(SrcMgr.getPresumedLineNumber(Loc)); +unsigned Line = SrcMgr.getPresumedLineNumber(Loc); +DiagnosticLines.insert(Line); +if (!AnnotationLines.contains(Line)) { + IntrusiveRefCntPtr DiagOpts( + new DiagnosticOptions()); + TextDiagnostic TD(llvm::errs(), AO.ASTCtx.getLangOpts(), +DiagOpts.get()); + TD.emitDiagnostic( + FullSourceLoc(Loc, SrcMgr), DiagnosticsEngine::Error, + "unexpected diagnostic", std::nullopt, std::nullopt); +} } EXPECT_THAT(DiagnosticLines, ContainerEq(AnnotationLines)); ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 477ee05 - [clang][dataflow] Add an `operator<<` for `OptionalTypeIdentifier`.
Author: Martin Braenne Date: 2023-07-20T12:52:53Z New Revision: 477ee05f83c6cc4f11b45e61e606934b99e72290 URL: https://github.com/llvm/llvm-project/commit/477ee05f83c6cc4f11b45e61e606934b99e72290 DIFF: https://github.com/llvm/llvm-project/commit/477ee05f83c6cc4f11b45e61e606934b99e72290.diff LOG: [clang][dataflow] Add an `operator<<` for `OptionalTypeIdentifier`. When tests fail in UncheckedOptionalAccessModelTest.cpp, this prints the name of the optional type instead of a blob of hex. Reviewed By: ymandel Differential Revision: https://reviews.llvm.org/D155788 Added: Modified: clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp Removed: diff --git a/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp b/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp index a181f284370886..719ec271e134c4 100644 --- a/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp @@ -1267,6 +1267,12 @@ struct OptionalTypeIdentifier { std::string TypeName; }; +static raw_ostream &operator<<(raw_ostream &OS, + const OptionalTypeIdentifier &TypeId) { + OS << TypeId.NamespaceName << "::" << TypeId.TypeName; + return OS; +} + class UncheckedOptionalAccessTest : public ::testing::TestWithParam { protected: ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 44f98d0 - [clang][dataflow] Eliminate duplication between `AggregateStorageLocation` and `StructValue`.
Author: Martin Braenne Date: 2023-07-24T13:20:01Z New Revision: 44f98d0101fe82352e7c5fa98f1b2e9dc1159200 URL: https://github.com/llvm/llvm-project/commit/44f98d0101fe82352e7c5fa98f1b2e9dc1159200 DIFF: https://github.com/llvm/llvm-project/commit/44f98d0101fe82352e7c5fa98f1b2e9dc1159200.diff LOG: [clang][dataflow] Eliminate duplication between `AggregateStorageLocation` and `StructValue`. After this change, `StructValue` is just a wrapper for an `AggregateStorageLocation`. For the wider context, see https://discourse.llvm.org/t/70086. ## How to review - Start by looking at the comments added / changed in Value.h, StorageLocation.h, and DataflowEnvironment.h. This will give you a good overview of the semantic changes. - Look at the corresponding .cpp files that implement the semantic changes. - Transfer.cpp, TypeErasedDataflowAnalysis.cpp, and RecordOps.cpp show how the core of the framework is affected by the semantic changes. - UncheckedOptionalAccessModel.cpp shows how this complex model is affected by the changes. - Many of the changes in the rest of the patch are mechanical in nature. Reviewed By: ymandel, xazax.hun Differential Revision: https://reviews.llvm.org/D155446 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h clang/include/clang/Analysis/FlowSensitive/StorageLocation.h clang/include/clang/Analysis/FlowSensitive/Value.h clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp clang/lib/Analysis/FlowSensitive/RecordOps.cpp clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp clang/unittests/Analysis/FlowSensitive/RecordOpsTest.cpp clang/unittests/Analysis/FlowSensitive/TestingSupport.h clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index 9d99b6771f71e1..5cf52ad3d72235 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -334,6 +334,31 @@ class Environment { /// in the environment. AggregateStorageLocation *getThisPointeeStorageLocation() const; + /// Returns the location of the result object for a record-type prvalue. + /// + /// In C++, prvalues of record type serve only a limited purpose: They can + /// only be used to initialize a result object (e.g. a variable or a + /// temporary). This function returns the location of that result object. + /// + /// When creating a prvalue of record type, we already need the storage + /// location of the result object to pass in `this`, even though prvalues are + /// otherwise not associated with storage locations. + /// + /// FIXME: Currently, this simply returns a stable storage location for `E`, + /// but this doesn't do the right thing in scenarios like the following: + /// ``` + /// MyClass c = some_condition()? MyClass(foo) : MyClass(bar); + /// ``` + /// Here, `MyClass(foo)` and `MyClass(bar)` will have two diff erent storage + /// locations, when in fact their storage locations should be the same. + /// Eventually, we want to propagate storage locations from result objects + /// down to the prvalues that initialize them, similar to the way that this is + /// done in Clang's CodeGen. + /// + /// Requirements: + /// `E` must be a prvalue of record type. + AggregateStorageLocation &getResultObjectLocation(const Expr &RecordPRValue); + /// Returns the return value of the current function. This can be null if: /// - The function has a void return type /// - No return value could be determined for the function, for example @@ -385,10 +410,16 @@ class Environment { PointerValue &getOrCreateNullPointerValue(QualType PointeeType); /// Creates a value appropriate for `Type`, if `Type` is supported, otherwise - /// return null. If `Type` is a pointer or reference type, creates all the - /// necessary storage locations and values for indirections until it finds a + /// returns null. + /// + /// If `Type` is a pointer or reference type, creates all the necessary + /// storage locations and values for indirections until it finds a /// non-pointer/non-reference type. /// + /// If `Type` is a class, struct, or union type, calls `setValue()` to + /// associate the `StructValue` with its storage location + /// (`StructValue::getAggregateLoc()`). + /// /// If `Type` is one of the following types, this function will always return /// a non-null pointer: /// - `bool` @@ -430,7 +461,7 @@ class En
[clang] c3cf630 - [clang][dataflow] Remove checks that test for consistency between `StructValue` and `AggregateStorageLocation`.
Author: Martin Braenne Date: 2023-07-24T13:20:04Z New Revision: c3cf630d80a26a3bfc0845592f86e555addce3ca URL: https://github.com/llvm/llvm-project/commit/c3cf630d80a26a3bfc0845592f86e555addce3ca DIFF: https://github.com/llvm/llvm-project/commit/c3cf630d80a26a3bfc0845592f86e555addce3ca.diff LOG: [clang][dataflow] Remove checks that test for consistency between `StructValue` and `AggregateStorageLocation`. Now that the redundancy between these two classes has been eliminated, these checks aren't needed any more. Reviewed By: ymandel, xazax.hun Differential Revision: https://reviews.llvm.org/D155813 Added: Modified: clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index 78f13a044ce64b..edd015bbf10937 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -27,11 +27,6 @@ #include #include -// FIXME: There are still remaining checks here that check for consistency -// between `StructValue` and `AggregateStorageLocation`. Now that the redundancy -// between these two classes has been eliminated, these checks aren't needed any -// more, so remove them. - namespace { using namespace clang; @@ -268,13 +263,7 @@ TEST(TransferTest, StructVarDecl) { const auto *FooLoc = cast(Env.getStorageLocation(*FooDecl)); -const auto *BarLoc = -cast(FooLoc->getChild(*BarDecl)); - -const auto *FooVal = cast(Env.getValue(*FooLoc)); -const auto *BarVal = -cast(getFieldValue(FooVal, *BarDecl, Env)); -EXPECT_EQ(Env.getValue(*BarLoc), BarVal); +EXPECT_TRUE(isa(getFieldValue(FooLoc, *BarDecl, Env))); }); } @@ -317,13 +306,7 @@ TEST(TransferTest, StructVarDeclWithInit) { const auto *FooLoc = cast(Env.getStorageLocation(*FooDecl)); -const auto *BarLoc = -cast(FooLoc->getChild(*BarDecl)); - -const auto *FooVal = cast(Env.getValue(*FooLoc)); -const auto *BarVal = -cast(getFieldValue(FooVal, *BarDecl, Env)); -EXPECT_EQ(Env.getValue(*BarLoc), BarVal); +EXPECT_TRUE(isa(getFieldValue(FooLoc, *BarDecl, Env))); }); } @@ -365,13 +348,7 @@ TEST(TransferTest, ClassVarDecl) { const auto *FooLoc = cast(Env.getStorageLocation(*FooDecl)); -const auto *BarLoc = -cast(FooLoc->getChild(*BarDecl)); - -const auto *FooVal = cast(Env.getValue(*FooLoc)); -const auto *BarVal = -cast(getFieldValue(FooVal, *BarDecl, Env)); -EXPECT_EQ(Env.getValue(*BarLoc), BarVal); +EXPECT_TRUE(isa(getFieldValue(FooLoc, *BarDecl, Env))); }); } @@ -1046,13 +1023,7 @@ TEST(TransferTest, StructParamDecl) { const auto *FooLoc = cast(Env.getStorageLocation(*FooDecl)); -const auto *BarLoc = -cast(FooLoc->getChild(*BarDecl)); - -const auto *FooVal = cast(Env.getValue(*FooLoc)); -const auto *BarVal = -cast(getFieldValue(FooVal, *BarDecl, Env)); -EXPECT_EQ(Env.getValue(*BarLoc), BarVal); +EXPECT_TRUE(isa(getFieldValue(FooLoc, *BarDecl, Env))); }); } @@ -1150,9 +1121,8 @@ TEST(TransferTest, StructMember) { const auto *FooLoc = cast(Env.getStorageLocation(*FooDecl)); -const auto *FooVal = cast(Env.getValue(*FooLoc)); const auto *BarVal = -cast(getFieldValue(FooVal, *BarDecl, Env)); +cast(getFieldValue(FooLoc, *BarDecl, Env)); const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); ASSERT_THAT(BazDecl, NotNull()); @@ -1392,9 +1362,8 @@ TEST(TransferTest, ClassMember) { const auto *FooLoc = cast(Env.getStorageLocation(*FooDecl)); -const auto *FooVal = cast(Env.getValue(*FooLoc)); const auto *BarVal = -cast(getFieldValue(FooVal, *BarDecl, Env)); +cast(getFieldValue(FooLoc, *BarDecl, Env)); const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); ASSERT_THAT(BazDecl, NotNull()); @@ -1553,14 +1522,10 @@ TEST(TransferTest, StructThisMember) { const auto *QuxLoc = cast(ThisLoc->getChild(*QuxDecl)); -const auto *QuxVal = dyn_cast(Env.getValue(*QuxLoc)); -ASSERT_THAT(QuxVal, NotNull()); +EXPECT_THAT(dyn_cast(Env.getValue(*QuxLoc)), NotNull()); -const auto *BazLoc = -cast(QuxLoc->getChild(*BazDecl)); const auto *BazVal = -cast(getFieldValue(QuxVal, *BazDecl, Env)); -EXPECT_EQ(Env.getValue(*BazLoc), BazVal); +cast(getFieldValue(QuxLoc, *BazDecl, Env)); const ValueDecl *QuuxDecl = findValueD
[clang] e6e83cb - [clang][dataflow] Don't crash when constructing an array of records.
Author: Martin Braenne Date: 2023-07-27T12:46:13Z New Revision: e6e83cbcc748a55a7eddce67b228298820cb9315 URL: https://github.com/llvm/llvm-project/commit/e6e83cbcc748a55a7eddce67b228298820cb9315 DIFF: https://github.com/llvm/llvm-project/commit/e6e83cbcc748a55a7eddce67b228298820cb9315.diff LOG: [clang][dataflow] Don't crash when constructing an array of records. When I wrote https://reviews.llvm.org/D155446, I assumed that a `CXXConstructExpr` would always have record type, but this isn't true: It can have array type when constructing an array of records. The code would crash in this situation because `createValue()` would return null. This patch includes a test that reproduces the crash without the other changes in the patch. Reviewed By: sammccall Differential Revision: https://reviews.llvm.org/D156402 Added: Modified: clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp index 0b7c22fe24e301..8f8f807a3a4b22 100644 --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -500,9 +500,14 @@ class TransferVisitor : public ConstStmtVisitor { return; } -auto &InitialVal = *cast(Env.createValue(S->getType())); -copyRecord(InitialVal.getAggregateLoc(), Env.getResultObjectLocation(*S), - Env); +// `CXXConstructExpr` can have array type if default-initializing an array +// of records, and we currently can't create values for arrays. So check if +// we've got a record type. +if (S->getType()->isRecordType()) { + auto &InitialVal = *cast(Env.createValue(S->getType())); + copyRecord(InitialVal.getAggregateLoc(), Env.getResultObjectLocation(*S), + Env); +} transferInlineCall(S, ConstructorDecl); } diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index 5acb28bd87abff..57c8a5f3589bc4 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -310,6 +310,28 @@ TEST(TransferTest, StructVarDeclWithInit) { }); } +TEST(TransferTest, StructArrayVarDecl) { + std::string Code = R"( +struct A {}; + +void target() { + A Array[2]; + // [[p]] +} + )"; + runDataflow( + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) { +const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); + +const ValueDecl *ArrayDecl = findValueDecl(ASTCtx, "Array"); + +// We currently don't create values for arrays. +ASSERT_THAT(Env.getValue(*ArrayDecl), IsNull()); + }); +} + TEST(TransferTest, ClassVarDecl) { std::string Code = R"( class A { ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 771d7d7 - [clang][dataflow] HTMLLogger: Don't crash if CFG contains unreachable blocks.
Author: Martin Braenne Date: 2023-07-27T13:02:42Z New Revision: 771d7d71df418f12c80632ec6c3488af98f9b196 URL: https://github.com/llvm/llvm-project/commit/771d7d71df418f12c80632ec6c3488af98f9b196 DIFF: https://github.com/llvm/llvm-project/commit/771d7d71df418f12c80632ec6c3488af98f9b196.diff LOG: [clang][dataflow] HTMLLogger: Don't crash if CFG contains unreachable blocks. Reviewed By: sammccall Differential Revision: https://reviews.llvm.org/D156411 Added: Modified: clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp index ee89e074f84676..ea9052b0e7171e 100644 --- a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp +++ b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp @@ -462,8 +462,9 @@ class HTMLLogger : public Logger { GraphS << " " << blockID(I) << " [id=" << blockID(I) << "]\n"; for (const auto *Block : CFG) { for (const auto &Succ : Block->succs()) { -GraphS << " " << blockID(Block->getBlockID()) << " -> " - << blockID(Succ.getReachableBlock()->getBlockID()) << "\n"; +if (Succ.getReachableBlock()) + GraphS << " " << blockID(Block->getBlockID()) << " -> " + << blockID(Succ.getReachableBlock()->getBlockID()) << "\n"; } } GraphS << "}\n"; ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 1b334a2 - [clang][dataflow] Eliminate `ReferenceValue`.
Author: Martin Braenne Date: 2023-07-27T13:14:47Z New Revision: 1b334a2ae7af8ad8b2e3367db6433f1bc7b2b1a4 URL: https://github.com/llvm/llvm-project/commit/1b334a2ae7af8ad8b2e3367db6433f1bc7b2b1a4 DIFF: https://github.com/llvm/llvm-project/commit/1b334a2ae7af8ad8b2e3367db6433f1bc7b2b1a4.diff LOG: [clang][dataflow] Eliminate `ReferenceValue`. There are no remaining uses of this class in the framework. This patch is part of the ongoing migration to strict handling of value categories (see https://discourse.llvm.org/t/70086 for details). Reviewed By: ymandel, xazax.hun, gribozavr2 Differential Revision: https://reviews.llvm.org/D155922 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h clang/include/clang/Analysis/FlowSensitive/Value.h clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp clang/lib/Analysis/FlowSensitive/DebugSupport.cpp clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp clang/lib/Analysis/FlowSensitive/Value.cpp clang/unittests/Analysis/FlowSensitive/ValueTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index 5cf52ad3d72235..6a6c6856cce95b 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -47,6 +47,7 @@ enum class SkipPast { /// No indirections should be skipped past. None, /// An optional reference should be skipped past. + /// This is deprecated; it is equivalent to `None` and will be removed. Reference, }; @@ -304,9 +305,10 @@ class Environment { /// `E` must be a glvalue or a `BuiltinType::BuiltinFn` void setStorageLocationStrict(const Expr &E, StorageLocation &Loc); - /// Returns the storage location assigned to `E` in the environment, applying - /// the `SP` policy for skipping past indirections, or null if `E` isn't - /// assigned a storage location in the environment. + /// Returns the storage location assigned to `E` in the environment, or null + /// if `E` isn't assigned a storage location in the environment. + /// + /// The `SP` parameter has no effect. /// /// This function is deprecated; prefer `getStorageLocationStrict()`. /// For details, see https://discourse.llvm.org/t/70086. @@ -490,12 +492,14 @@ class Environment { /// isn't assigned a value in the environment. Value *getValue(const StorageLocation &Loc) const; - /// Equivalent to `getValue(getStorageLocation(D, SP), SkipPast::None)` if `D` - /// is assigned a storage location in the environment, otherwise returns null. + /// Equivalent to `getValue(getStorageLocation(D))` if `D` is assigned a + /// storage location in the environment, otherwise returns null. Value *getValue(const ValueDecl &D) const; - /// Equivalent to `getValue(getStorageLocation(E, SP), SkipPast::None)` if `E` - /// is assigned a storage location in the environment, otherwise returns null. + /// Equivalent to `getValue(getStorageLocation(E, SP))` if `E` is assigned a + /// storage location in the environment, otherwise returns null. + /// + /// The `SP` parameter has no effect. /// /// This function is deprecated; prefer `getValueStrict()`. For details, see /// https://discourse.llvm.org/t/70086. @@ -672,9 +676,6 @@ class Environment { StorageLocation &createObjectInternal(const VarDecl *D, QualType Ty, const Expr *InitExpr); - StorageLocation &skip(StorageLocation &Loc, SkipPast SP) const; - const StorageLocation &skip(const StorageLocation &Loc, SkipPast SP) const; - /// Shared implementation of `pushCall` overloads. Note that unlike /// `pushCall`, this member is invoked on the environment of the callee, not /// of the caller. diff --git a/clang/include/clang/Analysis/FlowSensitive/Value.h b/clang/include/clang/Analysis/FlowSensitive/Value.h index 7d9a7b7d28254b..d1432fe8217a13 100644 --- a/clang/include/clang/Analysis/FlowSensitive/Value.h +++ b/clang/include/clang/Analysis/FlowSensitive/Value.h @@ -34,7 +34,6 @@ class Value { public: enum class Kind { Integer, -Reference, Pointer, Struct, @@ -165,23 +164,6 @@ class IntegerValue : public Value { } }; -/// Models a dereferenced pointer. For example, a reference in C++ or an lvalue -/// in C. -class ReferenceValue final : public Value { -public: - explicit ReferenceValue(StorageLocation &ReferentLoc) - : Value(Kind::Reference), ReferentLoc(ReferentLoc) {} - - static bool classof(const Value *Val) { -return Val->getKind() == Kind::Reference; - } - - StorageLocation &getReferentLoc() const { return ReferentLoc; } - -private: - StorageLocation &ReferentLoc; -}; - /// Models a symbolic pointer. Specifically, any value of type `T*`. class PointerVa
[clang] e95134b - [clang][dataflow] Reverse course on `getValue()` deprecation.
Author: Martin Braenne Date: 2023-07-27T13:14:49Z New Revision: e95134b9cb1885b0da929737858163486a5c399c URL: https://github.com/llvm/llvm-project/commit/e95134b9cb1885b0da929737858163486a5c399c DIFF: https://github.com/llvm/llvm-project/commit/e95134b9cb1885b0da929737858163486a5c399c.diff LOG: [clang][dataflow] Reverse course on `getValue()` deprecation. In the [value categories RFC](https://discourse.llvm.org/t/70086), I proposed that the end state of the migration should be that `getValue()` should only be legal to call on prvalues. As a stepping stone, to allow migrating off existing calls to `getValue()`, I proposed introducing `getValueStrict()`, which would already have the new semantics. However, I've now reconsidered this. Any expression, whether prvalue or glvalue, has a value, so really there isn't any reason to forbid calling `getValue()` on glvalues. I'm therefore removing the deprecation from `getValue()` and transitioning existing `getValueStrict()` calls back to `getValue()`. The other "strict" accessors are a different case. `setValueStrict()` should only be called on prvalues because glvalues need to have a storage location associated with them; it doesn't make sense to only set a value for them. And, of course, `getStorageLocationStrict()` and `setStorageLocationStrict()` should obviously only be called on glvalues because prvalues don't have storage locations. Reviewed By: ymandel, xazax.hun Differential Revision: https://reviews.llvm.org/D155921 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp clang/unittests/Analysis/FlowSensitive/SignAnalysisTest.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index 6a6c6856cce95b..460727973ed4c8 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -499,20 +499,14 @@ class Environment { /// Equivalent to `getValue(getStorageLocation(E, SP))` if `E` is assigned a /// storage location in the environment, otherwise returns null. /// - /// The `SP` parameter has no effect. - /// - /// This function is deprecated; prefer `getValueStrict()`. For details, see - /// https://discourse.llvm.org/t/70086. - Value *getValue(const Expr &E, SkipPast SP) const; + /// The `SP` parameter is deprecated and has no effect. New callers should + /// avoid passing this parameter. + Value *getValue(const Expr &E, SkipPast SP = SkipPast::None) const; /// Returns the `Value` assigned to the prvalue `E` in the environment, or /// null if `E` isn't assigned a value in the environment. /// - /// This function is the preferred alternative to - /// `getValue(const Expr &, SkipPast)`. Once the migration to strict handling - /// of value categories is complete (see https://discourse.llvm.org/t/70086), - /// `getValue()` will be removed and this function will be renamed to - /// `getValue()`. + /// This function is deprecated. Call `getValue(E)` instead. /// /// Requirements: /// diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index d3d5f3338ddf49..903d9ec300e2f6 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -686,7 +686,7 @@ void Environment::setValueStrict(const Expr &E, Value &Val) { assert(E.isPRValue()); if (auto *StructVal = dyn_cast(&Val)) { -if (auto *ExistingVal = cast_or_null(getValueStrict(E))) +if (auto *ExistingVal = cast_or_null(getValue(E))) assert(&ExistingVal->getAggregateLoc() == &StructVal->getAggregateLoc()); if (StorageLocation *ExistingLoc = getStorageLocation(E, SkipPast::None)) assert(ExistingLoc == &StructVal->getAggregateLoc()); @@ -724,9 +724,7 @@ Value *Environment::getValue(const Expr &E, SkipPast SP) const { Value *Environment::getValueStrict(const Expr &E) const { assert(E.isPRValue()); - Value *Val = getValue(E, SkipPast::None); - - return Val; + return getValue(E); } Value *Environment::createValue(QualType Type) { @@ -859,7 +857,7 @@ StorageLocation &Environment::createObjectInternal(const VarDecl *D, // assert that `InitExpr` is interpreted, rather than supplying a // default value (assuming we don't update the environment A
[clang] a1a63d6 - [clang][dataflow] Add two repros for non-convergence involving pointers in loops.
Author: Martin Braenne Date: 2023-08-23T07:03:16Z New Revision: a1a63d68a46882e051eedcb632723e15f2ee331b URL: https://github.com/llvm/llvm-project/commit/a1a63d68a46882e051eedcb632723e15f2ee331b DIFF: https://github.com/llvm/llvm-project/commit/a1a63d68a46882e051eedcb632723e15f2ee331b.diff LOG: [clang][dataflow] Add two repros for non-convergence involving pointers in loops. These are broken out from https://reviews.llvm.org/D156658, which it now seems obvious isn't the right way to solve the non-convergence. Instead, my plan is to address the non-convergence through pointer value widening, but the exact way this should be implemented is TBD. In the meantime, I think there's value in getting these repros submitted to record the current undesirable behavior. Reviewed By: ymandel, xazax.hun Differential Revision: https://reviews.llvm.org/D158513 Added: Modified: clang/unittests/Analysis/FlowSensitive/TestingSupport.h clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h index 11dc4ed76aa4fc..44dbf27a745867 100644 --- a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h +++ b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h @@ -402,8 +402,8 @@ llvm::Error checkDataflowWithNoopAnalysis( std::function< void(const llvm::StringMap> &, ASTContext &)> -VerifyResults, -DataflowAnalysisOptions Options, +VerifyResults = [](const auto &, auto &) {}, +DataflowAnalysisOptions Options = {BuiltinOptions()}, LangStandard::Kind Std = LangStandard::lang_cxx17, llvm::StringRef TargetFun = "target"); diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index 117230e14aa9e9..4c31de3c8085bd 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -2667,11 +2667,7 @@ TEST(TransferTest, CannotAnalyzeFunctionTemplate) { void target() {} )"; ASSERT_THAT_ERROR( - checkDataflowWithNoopAnalysis( - Code, - [](const llvm::StringMap> &Results, - ASTContext &ASTCtx) {}, - {BuiltinOptions()}), + checkDataflowWithNoopAnalysis(Code), llvm::FailedWithMessage("Cannot analyze templated declarations")); } @@ -2683,11 +2679,7 @@ TEST(TransferTest, CannotAnalyzeMethodOfClassTemplate) { }; )"; ASSERT_THAT_ERROR( - checkDataflowWithNoopAnalysis( - Code, - [](const llvm::StringMap> &Results, - ASTContext &ASTCtx) {}, - {BuiltinOptions()}), + checkDataflowWithNoopAnalysis(Code), llvm::FailedWithMessage("Cannot analyze templated declarations")); } @@ -3836,6 +3828,52 @@ TEST(TransferTest, LoopWithStructReferenceAssignmentConverges) { }); } +TEST(TransferTest, LoopDereferencingChangingPointerConverges) { + std::string Code = R"cc( +bool some_condition(); + +void target(int i1, int i2) { + int *p = &i1; + while (true) { +(void)*p; +if (some_condition()) + p = &i1; +else + p = &i2; + } +} + )cc"; + // FIXME: Implement pointer value widening to make analysis converge. + ASSERT_THAT_ERROR( + checkDataflowWithNoopAnalysis(Code), + llvm::FailedWithMessage("maximum number of iterations reached")); +} + +TEST(TransferTest, LoopDereferencingChangingRecordPointerConverges) { + std::string Code = R"cc( +struct Lookup { + int x; +}; + +bool some_condition(); + +void target(Lookup l1, Lookup l2) { + Lookup *l = &l1; + while (true) { +(void)l->x; +if (some_condition()) + l = &l1; +else + l = &l2; + } +} + )cc"; + // FIXME: Implement pointer value widening to make analysis converge. + ASSERT_THAT_ERROR( + checkDataflowWithNoopAnalysis(Code), + llvm::FailedWithMessage("maximum number of iterations reached")); +} + TEST(TransferTest, DoesNotCrashOnUnionThisExpr) { std::string Code = R"( union Union { ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 8c0acbf - [clang][dataflow] Avoid -Wunused-variable.
Author: Martin Braenne Date: 2023-07-28T07:57:50Z New Revision: 8c0acbf8370f29943798cd434cd0b91bbd554cdf URL: https://github.com/llvm/llvm-project/commit/8c0acbf8370f29943798cd434cd0b91bbd554cdf DIFF: https://github.com/llvm/llvm-project/commit/8c0acbf8370f29943798cd434cd0b91bbd554cdf.diff LOG: [clang][dataflow] Avoid -Wunused-variable. Added: Modified: clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index 903d9ec300e2f6..214e0c061ed7bc 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -686,9 +686,11 @@ void Environment::setValueStrict(const Expr &E, Value &Val) { assert(E.isPRValue()); if (auto *StructVal = dyn_cast(&Val)) { -if (auto *ExistingVal = cast_or_null(getValue(E))) +if ([[maybe_unused]] auto *ExistingVal = +cast_or_null(getValue(E))) assert(&ExistingVal->getAggregateLoc() == &StructVal->getAggregateLoc()); -if (StorageLocation *ExistingLoc = getStorageLocation(E, SkipPast::None)) +if ([[maybe_unused]] StorageLocation *ExistingLoc = +getStorageLocation(E, SkipPast::None)) assert(ExistingLoc == &StructVal->getAggregateLoc()); else setStorageLocation(E, StructVal->getAggregateLoc()); ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] f76f667 - [clang][dataflow] Use `Strict` accessors where we weren't using them yet.
Author: Martin Braenne Date: 2023-07-31T19:40:04Z New Revision: f76f6674d8221f59f9e515e3cc03ad07fa72fe46 URL: https://github.com/llvm/llvm-project/commit/f76f6674d8221f59f9e515e3cc03ad07fa72fe46 DIFF: https://github.com/llvm/llvm-project/commit/f76f6674d8221f59f9e515e3cc03ad07fa72fe46.diff LOG: [clang][dataflow] Use `Strict` accessors where we weren't using them yet. This eliminates all uses of the deprecated accessors. Reviewed By: ymandel, xazax.hun Differential Revision: https://reviews.llvm.org/D156672 Added: Modified: clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp clang/lib/Analysis/FlowSensitive/Transfer.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index 214e0c061ed7bc..c1cd00a73491ae 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -336,8 +336,8 @@ Environment Environment::pushCall(const CallExpr *Call) const { if (const auto *MethodCall = dyn_cast(Call)) { if (const Expr *Arg = MethodCall->getImplicitObjectArgument()) { if (!isa(Arg)) -Env.ThisPointeeLoc = cast( -getStorageLocation(*Arg, SkipPast::Reference)); + Env.ThisPointeeLoc = + cast(getStorageLocationStrict(*Arg)); // Otherwise (when the argument is `this`), retain the current // environment's `ThisPointeeLoc`. } @@ -832,9 +832,8 @@ StorageLocation &Environment::createObjectInternal(const VarDecl *D, // can happen that we can't see the initializer, so `InitExpr` may still // be null. if (InitExpr) { - if (auto *InitExprLoc = - getStorageLocation(*InitExpr, SkipPast::Reference)) -return *InitExprLoc; + if (auto *InitExprLoc = getStorageLocationStrict(*InitExpr)) + return *InitExprLoc; } // Even though we have an initializer, we might not get an @@ -913,16 +912,13 @@ getImplicitObjectLocation(const CXXMemberCallExpr &MCE, Expr *ImplicitObject = MCE.getImplicitObjectArgument(); if (ImplicitObject == nullptr) return nullptr; - StorageLocation *Loc = - Env.getStorageLocation(*ImplicitObject, SkipPast::Reference); - if (Loc == nullptr) -return nullptr; if (ImplicitObject->getType()->isPointerType()) { -if (auto *Val = cast_or_null(Env.getValue(*Loc))) +if (auto *Val = cast_or_null(Env.getValue(*ImplicitObject))) return &cast(Val->getPointeeLoc()); return nullptr; } - return cast(Loc); + return cast_or_null( + Env.getStorageLocationStrict(*ImplicitObject)); } AggregateStorageLocation *getBaseObjectLocation(const MemberExpr &ME, @@ -930,15 +926,13 @@ AggregateStorageLocation *getBaseObjectLocation(const MemberExpr &ME, Expr *Base = ME.getBase(); if (Base == nullptr) return nullptr; - StorageLocation *Loc = Env.getStorageLocation(*Base, SkipPast::Reference); - if (Loc == nullptr) -return nullptr; if (ME.isArrow()) { -if (auto *Val = cast_or_null(Env.getValue(*Loc))) +if (auto *Val = cast_or_null(Env.getValue(*Base))) return &cast(Val->getPointeeLoc()); return nullptr; } - return cast(Loc); + return cast_or_null( + Env.getStorageLocationStrict(*Base)); } std::vector getFieldsForInitListExpr(const RecordDecl *RD) { diff --git a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp index ef51402e171ed6..9b0daf2d95183f 100644 --- a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp +++ b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp @@ -254,10 +254,17 @@ class HTMLLogger : public Logger { if (ElementIndex > 0) { auto S = Iters.back().first->Elements[ElementIndex - 1].getAs(); -if (const Expr *E = S ? llvm::dyn_cast(S->getStmt()) : nullptr) - if (auto *Loc = State.Env.getStorageLocation(*E, SkipPast::None)) -JOS->attributeObject( -"value", [&] { ModelDumper(*JOS, State.Env).dump(*Loc); }); +if (const Expr *E = S ? llvm::dyn_cast(S->getStmt()) : nullptr) { + if (E->isPRValue()) { +if (auto *V = State.Env.getValue(*E)) + JOS->attributeObject( + "value", [&] { ModelDumper(*JOS, State.Env).dump(*V); }); + } else { +if (auto *Loc = State.Env.getStorageLocationStrict(*E)) + JOS->attributeObject( + "value", [&] { ModelDumper(*JOS, State.Env).dump(*Loc); }); + } +} } if (!ContextLogs.empty()) { JOS->attribute("logs", ContextLogs); diff --git a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessMode
[clang] 17ba278 - [clang][dataflow] Remove deprecated accessors as well as `SkipPast`.
Author: Martin Braenne Date: 2023-07-31T19:40:06Z New Revision: 17ba278f76116b12eb7a954c8963ee5a5a19c32b URL: https://github.com/llvm/llvm-project/commit/17ba278f76116b12eb7a954c8963ee5a5a19c32b DIFF: https://github.com/llvm/llvm-project/commit/17ba278f76116b12eb7a954c8963ee5a5a19c32b.diff LOG: [clang][dataflow] Remove deprecated accessors as well as `SkipPast`. Depends On D156672 Reviewed By: ymandel, xazax.hun Differential Revision: https://reviews.llvm.org/D156673 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index 460727973ed4c8..bd89c7e5c74a3c 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -38,19 +38,6 @@ namespace clang { namespace dataflow { -/// Indicates what kind of indirections should be skipped past when retrieving -/// storage locations or values. -/// -/// FIXME: Consider renaming this or replacing it with a more appropriate model. -/// See the discussion in https://reviews.llvm.org/D116596 for context. -enum class SkipPast { - /// No indirections should be skipped past. - None, - /// An optional reference should be skipped past. - /// This is deprecated; it is equivalent to `None` and will be removed. - Reference, -}; - /// Indicates the result of a tentative comparison. enum class ComparisonResult { Same, @@ -280,40 +267,15 @@ class Environment { /// refers directly to the referenced object, not a `ReferenceValue`. StorageLocation *getStorageLocation(const ValueDecl &D) const; - /// Assigns `Loc` as the storage location of `E` in the environment. - /// - /// This function is deprecated; prefer `setStorageLocationStrict()`. - /// For details, see https://discourse.llvm.org/t/70086. - /// - /// Requirements: - /// - /// `E` must not be assigned a storage location in the environment. - void setStorageLocation(const Expr &E, StorageLocation &Loc); - /// Assigns `Loc` as the storage location of the glvalue `E` in the /// environment. /// - /// This function is the preferred alternative to - /// `setStorageLocation(const Expr &, StorageLocation &)`. Once the migration - /// to strict handling of value categories is complete (see - /// https://discourse.llvm.org/t/70086), `setStorageLocation()` will be - /// removed and this function will be renamed to `setStorageLocation()`. - /// /// Requirements: /// /// `E` must not be assigned a storage location in the environment. /// `E` must be a glvalue or a `BuiltinType::BuiltinFn` void setStorageLocationStrict(const Expr &E, StorageLocation &Loc); - /// Returns the storage location assigned to `E` in the environment, or null - /// if `E` isn't assigned a storage location in the environment. - /// - /// The `SP` parameter has no effect. - /// - /// This function is deprecated; prefer `getStorageLocationStrict()`. - /// For details, see https://discourse.llvm.org/t/70086. - StorageLocation *getStorageLocation(const Expr &E, SkipPast SP) const; - /// Returns the storage location assigned to the glvalue `E` in the /// environment, or null if `E` isn't assigned a storage location in the /// environment. @@ -321,12 +283,6 @@ class Environment { /// If the storage location for `E` is associated with a /// `ReferenceValue RefVal`, returns `RefVal.getReferentLoc()` instead. /// - /// This function is the preferred alternative to - /// `getStorageLocation(const Expr &, SkipPast)`. Once the migration - /// to strict handling of value categories is complete (see - /// https://discourse.llvm.org/t/70086), `getStorageLocation()` will be - /// removed and this function will be renamed to `getStorageLocation()`. - /// /// Requirements: /// `E` must be a glvalue or a `BuiltinType::BuiltinFn` StorageLocation *getStorageLocationStrict(const Expr &E) const; @@ -498,20 +454,7 @@ class Environment { /// Equivalent to `getValue(getStorageLocation(E, SP))` if `E` is assigned a /// storage location in the environment, otherwise returns null. - /// - /// The `SP` parameter is deprecated and has no effect. New callers should - /// avoid passing this parameter. - Value *getValue(const Expr &E, SkipPast SP = SkipPast::None) const; - - /// Returns the `Value` assigned to the prvalue `E` in the environment, or - /// null if `E` isn't assigned a value in the environment. - /// - /// This function is deprecated. Call `getValue(E)` instead. - /// - /// Requirements: - /// - /// `E` must be a prvalue - Value *getValueStrict(const Expr &E) const; + Value *getValue(const Expr &E) const; // FIXME
[clang] b244b6a - [clang][dataflow] Remove `Strict` suffix from accessors.
Author: Martin Braenne Date: 2023-07-31T19:40:09Z New Revision: b244b6ae0b2153521c5e55ff4705a88618f503aa URL: https://github.com/llvm/llvm-project/commit/b244b6ae0b2153521c5e55ff4705a88618f503aa DIFF: https://github.com/llvm/llvm-project/commit/b244b6ae0b2153521c5e55ff4705a88618f503aa.diff LOG: [clang][dataflow] Remove `Strict` suffix from accessors. For the time being, we're keeping the `Strict` versions around as deprecated synonyms so that clients can be migrated, but these synonyms will be removed soon. Depends On D156673 Reviewed By: ymandel, xazax.hun Differential Revision: https://reviews.llvm.org/D156674 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp clang/unittests/Analysis/FlowSensitive/SignAnalysisTest.cpp clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index bd89c7e5c74a3c..0e5cfad263c797 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -274,7 +274,12 @@ class Environment { /// /// `E` must not be assigned a storage location in the environment. /// `E` must be a glvalue or a `BuiltinType::BuiltinFn` - void setStorageLocationStrict(const Expr &E, StorageLocation &Loc); + void setStorageLocation(const Expr &E, StorageLocation &Loc); + + /// Deprecated synonym for `setStorageLocation()`. + void setStorageLocationStrict(const Expr &E, StorageLocation &Loc) { +setStorageLocation(E, Loc); + } /// Returns the storage location assigned to the glvalue `E` in the /// environment, or null if `E` isn't assigned a storage location in the @@ -285,7 +290,12 @@ class Environment { /// /// Requirements: /// `E` must be a glvalue or a `BuiltinType::BuiltinFn` - StorageLocation *getStorageLocationStrict(const Expr &E) const; + StorageLocation *getStorageLocation(const Expr &E) const; + + /// Deprecated synonym for `getStorageLocation()`. + StorageLocation *getStorageLocationStrict(const Expr &E) const { +return getStorageLocation(E); + } /// Returns the storage location assigned to the `this` pointee in the /// environment or null if the `this` pointee has no assigned storage location @@ -442,7 +452,10 @@ class Environment { /// same as that of any `StructValue` that has already been associated with /// `E`. This is to guarantee that the result object initialized by a prvalue /// `StructValue` has a durable storage location. - void setValueStrict(const Expr &E, Value &Val); + void setValue(const Expr &E, Value &Val); + + /// Deprecated synonym for `setValue()`. + void setValueStrict(const Expr &E, Value &Val) { setValue(E, Val); } /// Returns the value assigned to `Loc` in the environment or null if `Loc` /// isn't assigned a value in the environment. @@ -585,11 +598,11 @@ class Environment { // The copy-constructor is for use in fork() only. Environment(const Environment &) = default; - /// Internal version of `setStorageLocationStrict()` that doesn't check if the + /// Internal version of `setStorageLocation()` that doesn't check if the /// expression is a prvalue. void setStorageLocationInternal(const Expr &E, StorageLocation &Loc); - /// Internal version of `getStorageLocationStrict()` that doesn't check if the + /// Internal version of `getStorageLocation()` that doesn't check if the /// expression is a prvalue. StorageLocation *getStorageLocationInternal(const Expr &E) const; diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index 48f8e63a165efe..503158c91c3f4f 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -337,7 +337,7 @@ Environment Environment::pushCall(const CallExpr *Call) const { if (const Expr *Arg = MethodCall->getImplicitObjectArgument()) { if (!isa(Arg)) Env.ThisPointeeLoc = - cast(getStorageLocationStrict(*Arg)); + cast(getStorageLocation(*Arg)); // Otherwise (when the argument is `this`), retain the current // environment's `ThisPointeeLoc`. } @@ -396,10 +396,10 @@ void Environment::popCall(const CallExpr *Call, const Environment &CalleeEnv) {
[clang] 8c1a519 - [clang][dataflow] Remove deprecated `Strict` accessors.
Author: Martin Braenne Date: 2023-08-01T20:07:00Z New Revision: 8c1a519ee423f4097092095a44ba850bf0dd498d URL: https://github.com/llvm/llvm-project/commit/8c1a519ee423f4097092095a44ba850bf0dd498d DIFF: https://github.com/llvm/llvm-project/commit/8c1a519ee423f4097092095a44ba850bf0dd498d.diff LOG: [clang][dataflow] Remove deprecated `Strict` accessors. Reviewed By: ymandel, xazax.hun Differential Revision: https://reviews.llvm.org/D156790 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index 0e5cfad263c797..7ac2ff3102adcd 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -276,11 +276,6 @@ class Environment { /// `E` must be a glvalue or a `BuiltinType::BuiltinFn` void setStorageLocation(const Expr &E, StorageLocation &Loc); - /// Deprecated synonym for `setStorageLocation()`. - void setStorageLocationStrict(const Expr &E, StorageLocation &Loc) { -setStorageLocation(E, Loc); - } - /// Returns the storage location assigned to the glvalue `E` in the /// environment, or null if `E` isn't assigned a storage location in the /// environment. @@ -292,11 +287,6 @@ class Environment { /// `E` must be a glvalue or a `BuiltinType::BuiltinFn` StorageLocation *getStorageLocation(const Expr &E) const; - /// Deprecated synonym for `getStorageLocation()`. - StorageLocation *getStorageLocationStrict(const Expr &E) const { -return getStorageLocation(E); - } - /// Returns the storage location assigned to the `this` pointee in the /// environment or null if the `this` pointee has no assigned storage location /// in the environment. @@ -454,9 +444,6 @@ class Environment { /// `StructValue` has a durable storage location. void setValue(const Expr &E, Value &Val); - /// Deprecated synonym for `setValue()`. - void setValueStrict(const Expr &E, Value &Val) { setValue(E, Val); } - /// Returns the value assigned to `Loc` in the environment or null if `Loc` /// isn't assigned a value in the environment. Value *getValue(const StorageLocation &Loc) const; ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 9ecdbe3 - [clang][dataflow] Rename `AggregateStorageLocation` to `RecordStorageLocation` and `StructValue` to `RecordValue`.
Author: Martin Braenne Date: 2023-08-01T20:29:40Z New Revision: 9ecdbe3855a8048989a507ff8d470aee4d407589 URL: https://github.com/llvm/llvm-project/commit/9ecdbe3855a8048989a507ff8d470aee4d407589 DIFF: https://github.com/llvm/llvm-project/commit/9ecdbe3855a8048989a507ff8d470aee4d407589.diff LOG: [clang][dataflow] Rename `AggregateStorageLocation` to `RecordStorageLocation` and `StructValue` to `RecordValue`. - Both of these constructs are used to represent structs, classes, and unions; Clang uses the collective term "record" for these. - The term "aggregate" in `AggregateStorageLocation` implies that, at some point, the intention may have been to use it also for arrays, but it don't think it's possible to use it for arrays. Records and arrays are very different and therefore need to be modeled differently. Records have a fixed set of named fields, which can have different type; arrays have a variable number of elements, but they all have the same type. - Futhermore, "aggregate" has a very specific meaning in C++ (https://en.cppreference.com/w/cpp/language/aggregate_initialization). Aggregates of class type may not have any user-declared or inherited constructors, no private or protected non-static data members, no virtual member functions, and so on, but we use `AggregateStorageLocations` to model all objects of class type. In addition, for consistency, we also rename the following: - `getAggregateLoc()` (in `RecordValue`, formerly known as `StructValue`) to simply `getLoc()`. - `refreshStructValue()` to `refreshRecordValue()` We keep the old names around as deprecated synonyms to enable clients to be migrated to the new names. Reviewed By: ymandel, xazax.hun Differential Revision: https://reviews.llvm.org/D156788 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h clang/include/clang/Analysis/FlowSensitive/RecordOps.h clang/include/clang/Analysis/FlowSensitive/StorageLocation.h clang/include/clang/Analysis/FlowSensitive/Value.h clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp clang/lib/Analysis/FlowSensitive/DebugSupport.cpp clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp clang/lib/Analysis/FlowSensitive/RecordOps.cpp clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp clang/unittests/Analysis/FlowSensitive/RecordOpsTest.cpp clang/unittests/Analysis/FlowSensitive/TestingSupport.h clang/unittests/Analysis/FlowSensitive/TransferTest.cpp clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index 7ac2ff3102adcd..f812c01d42040b 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -76,7 +76,7 @@ class Environment { virtual ComparisonResult compare(QualType Type, const Value &Val1, const Environment &Env1, const Value &Val2, const Environment &Env2) { - // FIXME: Consider adding QualType to StructValue and removing the Type + // FIXME: Consider adding QualType to RecordValue and removing the Type // argument here. return ComparisonResult::Unknown; } @@ -290,7 +290,7 @@ class Environment { /// Returns the storage location assigned to the `this` pointee in the /// environment or null if the `this` pointee has no assigned storage location /// in the environment. - AggregateStorageLocation *getThisPointeeStorageLocation() const; + RecordStorageLocation *getThisPointeeStorageLocation() const; /// Returns the location of the result object for a record-type prvalue. /// @@ -315,7 +315,7 @@ class Environment { /// /// Requirements: /// `E` must be a prvalue of record type. - AggregateStorageLocation &getResultObjectLocation(const Expr &RecordPRValue); + RecordStorageLocation &getResultObjectLocation(const Expr &RecordPRValue); /// Returns the return value of the current function. This can be null if: /// - The function has a void return type @@ -375,8 +375,8 @@ class Environment { /// non-pointer/non-reference type. /// /// If `Type` is a class, struct, or union type, calls `setValue()` to - /// associate the `StructValue` with its storage location - /// (`StructValue::getAggregateLoc()`). + /// associate the `RecordValue` with its storage location + /// (`RecordValue::getLoc()`). /// /// I
[clang] e6cd409 - [clang][dataflow] In `ControlFlowContext`, handle `Decl` by reference instead of pointer.
Author: Martin Braenne Date: 2023-08-03T06:59:29Z New Revision: e6cd409fc6396cb13c59b4a5190abc4b856f22a5 URL: https://github.com/llvm/llvm-project/commit/e6cd409fc6396cb13c59b4a5190abc4b856f22a5 DIFF: https://github.com/llvm/llvm-project/commit/e6cd409fc6396cb13c59b4a5190abc4b856f22a5.diff LOG: [clang][dataflow] In `ControlFlowContext`, handle `Decl` by reference instead of pointer. `build()` guarantees that we'll always have a `Decl`, so we can simplify the code. Reviewed By: ymandel, xazax.hun Differential Revision: https://reviews.llvm.org/D156859 Added: Modified: clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp clang/lib/Analysis/FlowSensitive/Logger.cpp clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h b/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h index bb36ed237c1e34..a45bb0635a2f36 100644 --- a/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h +++ b/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h @@ -48,7 +48,7 @@ class ControlFlowContext { /// Returns the `Decl` containing the statement used to construct the CFG, if /// available. - const Decl *getDecl() const { return ContainingDecl; } + const Decl &getDecl() const { return ContainingDecl; } /// Returns the CFG that is stored in this context. const CFG &getCFG() const { return *Cfg; } @@ -64,9 +64,7 @@ class ControlFlowContext { } private: - // FIXME: Once the deprecated `build` method is removed, mark `D` as "must not - // be null" and add an assertion. - ControlFlowContext(const Decl *D, std::unique_ptr Cfg, + ControlFlowContext(const Decl &D, std::unique_ptr Cfg, llvm::DenseMap StmtToBlock, llvm::BitVector BlockReachable) : ContainingDecl(D), Cfg(std::move(Cfg)), @@ -74,7 +72,7 @@ class ControlFlowContext { BlockReachable(std::move(BlockReachable)) {} /// The `Decl` containing the statement used to construct the CFG. - const Decl *ContainingDecl; + const Decl &ContainingDecl; std::unique_ptr Cfg; llvm::DenseMap StmtToBlock; llvm::BitVector BlockReachable; diff --git a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp index c80525dc4f34f2..d5e0b443caf301 100644 --- a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp +++ b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp @@ -105,7 +105,7 @@ ControlFlowContext::build(const Decl &D, Stmt &S, ASTContext &C) { llvm::BitVector BlockReachable = findReachableBlocks(*Cfg); - return ControlFlowContext(&D, std::move(Cfg), std::move(StmtToBlock), + return ControlFlowContext(D, std::move(Cfg), std::move(StmtToBlock), std::move(BlockReachable)); } diff --git a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp index 9ec0160b1e3fe4..b1bfe10db20243 100644 --- a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp +++ b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp @@ -166,15 +166,14 @@ class HTMLLogger : public Logger { this->CFG = &CFG; *OS << llvm::StringRef(HTMLLogger_html).split("").first; -if (const auto *D = CFG.getDecl()) { - const auto &SM = A.getASTContext().getSourceManager(); - *OS << ""; - if (const auto *ND = dyn_cast(D)) -*OS << ND->getNameAsString() << " at "; - *OS << SM.getFilename(D->getLocation()) << ":" - << SM.getSpellingLineNumber(D->getLocation()); - *OS << "\n"; -}; +const auto &D = CFG.getDecl(); +const auto &SM = A.getASTContext().getSourceManager(); +*OS << ""; +if (const auto *ND = dyn_cast(&D)) + *OS << ND->getNameAsString() << " at "; +*OS << SM.getFilename(D.getLocation()) << ":" +<< SM.getSpellingLineNumber(D.getLocation()); +*OS << "\n"; *OS << "" << HTMLLogger_css << "\n"; *OS << "" << HTMLLogger_js << "\n"; @@ -307,9 +306,7 @@ class HTMLLogger : public Logger { // tokens are associated with, and even which BB element (so that clicking // can select the right element). void writeCode() { -if (!CFG->getDecl()) - return; -const auto &AST = CFG->getDecl()->getASTContext(); +const auto &AST = CFG->getDecl().getASTContext(); bool Invalid = false; // Extract the source code from the original file. @@ -317,7 +314,7 @@ class HTMLLogger : public Logger { // indentation to worry about), but we need the boundaries of particular // AST nodes and the printer doesn't provide this. auto Range = clang::Lexer::makeFileChar
[clang] 880f306 - [clang][dataflow] Add a test for a struct that is directly self-referential through a reference.
Author: Martin Braenne Date: 2023-07-04T12:06:13Z New Revision: 880f306226fcb97d85d422480954eb8765ff31c7 URL: https://github.com/llvm/llvm-project/commit/880f306226fcb97d85d422480954eb8765ff31c7 DIFF: https://github.com/llvm/llvm-project/commit/880f306226fcb97d85d422480954eb8765ff31c7.diff LOG: [clang][dataflow] Add a test for a struct that is directly self-referential through a reference. The ongoing migration to strict handling of value categories (see https://discourse.llvm.org/t/70086) will change the way we handle fields of reference type, and I want to put a test in place that makes sure we continue to handle this special case correctly. Depends On D154420 Reviewed By: gribozavr2, xazax.hun Differential Revision: https://reviews.llvm.org/D154421 Added: Modified: clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index f7210d29d06cc9..2ccd3e82baadc9 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -656,6 +656,30 @@ TEST(TransferTest, SelfReferentialPointerVarDecl) { }); } +TEST(TransferTest, DirectlySelfReferentialReference) { + std::string Code = R"( +struct target { + target() { +(void)0; +// [[p]] + } + target &self = *this; +}; + )"; + runDataflow( + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) { +const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); +const ValueDecl *SelfDecl = findValueDecl(ASTCtx, "self"); + +auto *ThisLoc = Env.getThisPointeeStorageLocation(); +auto *RefVal = +cast(Env.getValue(ThisLoc->getChild(*SelfDecl))); +ASSERT_EQ(&RefVal->getReferentLoc(), ThisLoc); + }); +} + TEST(TransferTest, MultipleVarsDecl) { std::string Code = R"( void target() { ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 1e7329c - [clang][dataflow] Model variables / fields / funcs used in default initializers.
Author: Martin Braenne Date: 2023-07-04T12:06:10Z New Revision: 1e7329cd79c53165f113edfe6a2ff06d12899632 URL: https://github.com/llvm/llvm-project/commit/1e7329cd79c53165f113edfe6a2ff06d12899632 DIFF: https://github.com/llvm/llvm-project/commit/1e7329cd79c53165f113edfe6a2ff06d12899632.diff LOG: [clang][dataflow] Model variables / fields / funcs used in default initializers. The newly added test fails without the other changes in this patch. Reviewed By: sammccall, gribozavr2 Differential Revision: https://reviews.llvm.org/D154420 Added: Modified: clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index 689f8abb51c8e0..4a11c09a44f63b 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -194,6 +194,8 @@ getFieldsGlobalsAndFuncs(const Stmt &S, for (auto *Child : S.children()) if (Child != nullptr) getFieldsGlobalsAndFuncs(*Child, Fields, Vars, Funcs); + if (const auto *DefaultInit = dyn_cast(&S)) +getFieldsGlobalsAndFuncs(*DefaultInit->getExpr(), Fields, Vars, Funcs); if (auto *DS = dyn_cast(&S)) { if (DS->isSingleDecl()) diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index 210b85f7ae8d67..f7210d29d06cc9 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -5547,4 +5547,40 @@ TEST(TransferTest, AnonymousStructWithInitializer) { }); } +TEST(TransferTest, AnonymousStructWithReferenceField) { + std::string Code = R"( +int global_i = 0; +struct target { + target() { +(void)0; +// [[p]] + } + struct { +int &i = global_i; + }; +}; + )"; + runDataflow( + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) { +const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); +const ValueDecl *GlobalIDecl = findValueDecl(ASTCtx, "global_i"); +const ValueDecl *IDecl = findValueDecl(ASTCtx, "i"); +const IndirectFieldDecl *IndirectField = +findIndirectFieldDecl(ASTCtx, "i"); + +auto *ThisLoc = + cast(Env.getThisPointeeStorageLocation()); +auto &AnonStruct = cast(ThisLoc->getChild( +*cast(IndirectField->chain().front(; + +auto *RefVal = +cast(Env.getValue(AnonStruct.getChild(*IDecl))); + +ASSERT_EQ(&RefVal->getReferentLoc(), + Env.getStorageLocation(*GlobalIDecl)); + }); +} + } // namespace ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] d0be47c - [clang][dataflow] Make `runDataflowReturnError()` a non-template function.
Author: Martin Braenne Date: 2023-07-04T12:44:49Z New Revision: d0be47c51cfdb8b94eb20279c02e8e2875380919 URL: https://github.com/llvm/llvm-project/commit/d0be47c51cfdb8b94eb20279c02e8e2875380919 DIFF: https://github.com/llvm/llvm-project/commit/d0be47c51cfdb8b94eb20279c02e8e2875380919.diff LOG: [clang][dataflow] Make `runDataflowReturnError()` a non-template function. It turns out this didn't need to be a template at all. Likewise, change callers to they're non-template functions. Also, correct / clarify some comments in RecordOps.h. This is in response to post-commit comments on https://reviews.llvm.org/D153006. Reviewed By: gribozavr2 Differential Revision: https://reviews.llvm.org/D154339 Added: Modified: clang/include/clang/Analysis/FlowSensitive/RecordOps.h clang/unittests/Analysis/FlowSensitive/RecordOpsTest.cpp clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp clang/unittests/Analysis/FlowSensitive/TestingSupport.h clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/RecordOps.h b/clang/include/clang/Analysis/FlowSensitive/RecordOps.h index f5a0a5a501c119..c9c302b9199bf2 100644 --- a/clang/include/clang/Analysis/FlowSensitive/RecordOps.h +++ b/clang/include/clang/Analysis/FlowSensitive/RecordOps.h @@ -23,7 +23,7 @@ namespace dataflow { /// /// This performs a deep copy, i.e. it copies every field and recurses on /// fields of record type. It also copies properties from the `StructValue` -/// associated with `Dst` to the `StructValue` associated with `Src` (if these +/// associated with `Src` to the `StructValue` associated with `Dst` (if these /// `StructValue`s exist). /// /// If there is a `StructValue` associated with `Dst` in the environment, this @@ -52,6 +52,11 @@ void copyRecord(AggregateStorageLocation &Src, AggregateStorageLocation &Dst, /// refer to the same storage location. If `StructValue`s are associated with /// `Loc1` and `Loc2`, it also compares the properties on those `StructValue`s. /// +/// Note on how to interpret the result: +/// - If this returns true, the records are guaranteed to be equal at runtime. +/// - If this returns false, the records may still be equal at runtime; our +/// analysis merely cannot guarantee that they will be equal. +/// /// Requirements: /// /// `Src` and `Dst` must have the same canonical unqualified type. diff --git a/clang/unittests/Analysis/FlowSensitive/RecordOpsTest.cpp b/clang/unittests/Analysis/FlowSensitive/RecordOpsTest.cpp index a89011e423cd27..1f5fce1f2dd467 100644 --- a/clang/unittests/Analysis/FlowSensitive/RecordOpsTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/RecordOpsTest.cpp @@ -16,14 +16,18 @@ namespace dataflow { namespace test { namespace { -template -void runDataflow(llvm::StringRef Code, VerifyResultsT VerifyResults, - LangStandard::Kind Std = LangStandard::lang_cxx17, - llvm::StringRef TargetFun = "target") { +void runDataflow( +llvm::StringRef Code, +std::function< +void(const llvm::StringMap> &, + ASTContext &)> +VerifyResults, +LangStandard::Kind Std = LangStandard::lang_cxx17, +llvm::StringRef TargetFun = "target") { ASSERT_THAT_ERROR( - runDataflowReturnError(Code, VerifyResults, - DataflowAnalysisOptions{BuiltinOptions{}}, Std, - TargetFun), + checkDataflowWithNoopAnalysis(Code, VerifyResults, +DataflowAnalysisOptions{BuiltinOptions{}}, +Std, TargetFun), llvm::Succeeded()); } diff --git a/clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp b/clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp index a88b8d88c74c07..72bdfee26fe7f3 100644 --- a/clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp @@ -153,6 +153,43 @@ test::buildStatementToAnnotationMapping(const FunctionDecl *Func, return Result; } +llvm::Error test::checkDataflowWithNoopAnalysis( +llvm::StringRef Code, +std::function< +void(const llvm::StringMap> &, + ASTContext &)> +VerifyResults, +DataflowAnalysisOptions Options, LangStandard::Kind Std, +llvm::StringRef TargetFun) { + using ast_matchers::hasName; + llvm::SmallVector ASTBuildArgs = { + // -fnodelayed-template-parsing is the default everywhere but on Windows. + // Set it explicitly so that tests behave the same on Windows as on other + // platforms. + "-fsyntax-only", "-fno-delayed-template-parsing", + "-std=" + + std::string(LangStandard::getLangStandardForKind(Std).getName())}; + AnalysisInputs AI( + Code, hasName(TargetFun), + [UseBuiltinModel = Options.BuiltinOpts.has
[clang] ca01be5 - [clang][dataflow] Bug fix: `BuiltinFnToFnPtr` cast does not produce a pointer.
Author: Martin Braenne Date: 2023-07-06T06:56:02Z New Revision: ca01be54c1e94c552eceb00fc21b4363fae63d6c URL: https://github.com/llvm/llvm-project/commit/ca01be54c1e94c552eceb00fc21b4363fae63d6c DIFF: https://github.com/llvm/llvm-project/commit/ca01be54c1e94c552eceb00fc21b4363fae63d6c.diff LOG: [clang][dataflow] Bug fix: `BuiltinFnToFnPtr` cast does not produce a pointer. See comments in the code for details. Reviewed By: xazax.hun Differential Revision: https://reviews.llvm.org/D154479 Added: Modified: clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp index 5ad176dc1cdbe9..d69e0f5a5e1030 100644 --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -419,8 +419,7 @@ class TransferVisitor : public ConstStmtVisitor { // FIXME: Implement pointers to members. For now, don't associate a value // with this expression. break; -case CK_FunctionToPointerDecay: -case CK_BuiltinFnToFnPtr: { +case CK_FunctionToPointerDecay: { StorageLocation *PointeeLoc = Env.getStorageLocation(*SubExpr, SkipPast::Reference); if (PointeeLoc == nullptr) @@ -432,6 +431,12 @@ class TransferVisitor : public ConstStmtVisitor { Env.setValue(PointerLoc, PointerVal); break; } +case CK_BuiltinFnToFnPtr: + // Despite its name, the result type of `BuiltinFnToFnPtr` is a function, + // not a function pointer. In addition, builtin functions can only be + // called directly; it is not legal to take their address. We therefore + // don't need to create a value or storage location for them. + break; default: break; } diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index 3f99ff5652ce28..83ea176034c0d7 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -5480,8 +5480,8 @@ TEST(TransferTest, FunctionToPointerDecayHasValue) { }); } -// Check that the pointer that a builtin function decays to is associated with -// a value. +// Check that a builtin function is not associated with a value. (It's only +// possible to call builtin functions directly, not take their address.) TEST(TransferTest, BuiltinFunctionModeled) { std::string Code = R"( void target() { @@ -5509,7 +5509,7 @@ TEST(TransferTest, BuiltinFunctionModeled) { ASTCtx)); ASSERT_THAT(ImplicitCast, NotNull()); -EXPECT_THAT(Env.getValueStrict(*ImplicitCast), NotNull()); +EXPECT_THAT(Env.getValueStrict(*ImplicitCast), IsNull()); }); } ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] e8a1560 - [clang][dataflow] Various changes to handling of modeled fields.
Author: Martin Braenne Date: 2023-07-10T06:45:53Z New Revision: e8a1560d1de9514d3f1631388fe966476778e540 URL: https://github.com/llvm/llvm-project/commit/e8a1560d1de9514d3f1631388fe966476778e540 DIFF: https://github.com/llvm/llvm-project/commit/e8a1560d1de9514d3f1631388fe966476778e540.diff LOG: [clang][dataflow] Various changes to handling of modeled fields. - Rename `getReferencedFields()` to `getModeledFields()`. Move the logic that returns all object fields when doing a context-sensitive analysis to here from `DataflowAnalysisContext::createStorageLocation()`. I think all callers of the previous `getReferencedFields()` should use this logic; the fact that they were not doing so looks like a bug. - Make `getModeledFields()` public. I have an upcoming patch that will need to use this function from Transfer.cpp, and there doesn't seem to be any reason why this function should not be public. - Use a `SmallSetVector` to get deterministic iteration order. I have a pending patch where I'm getting flaky tests because `Environment::createValueUnlessSelfReferential()` is non-deterministically populating different fields depending on the iteration order. This change fixes those flaky tests. Reviewed By: gribozavr2 Differential Revision: https://reviews.llvm.org/D154586 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h index 2a31a3477e8ceb..e5c325b876bd7a 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h @@ -51,8 +51,12 @@ class Logger; const Expr &ignoreCFGOmittedNodes(const Expr &E); const Stmt &ignoreCFGOmittedNodes(const Stmt &S); +/// A set of `FieldDecl *`. Use `SmallSetVector` to guarantee deterministic +/// iteration order. +using FieldSet = llvm::SmallSetVector; + /// Returns the set of all fields in the type. -llvm::DenseSet getObjectFields(QualType Type); +FieldSet getObjectFields(QualType Type); struct ContextSensitiveOptions { /// The maximum depth to analyze. A value of zero is equivalent to disabling @@ -181,6 +185,10 @@ class DataflowAnalysisContext { /// been stored in flow conditions. Solver::Result querySolver(llvm::SetVector Constraints); + /// Returns the fields of `Type`, limited to the set of fields modeled by this + /// context. + FieldSet getModeledFields(QualType Type); + private: friend class Environment; @@ -196,11 +204,7 @@ class DataflowAnalysisContext { }; // Extends the set of modeled field declarations. - void addModeledFields(const llvm::DenseSet &Fields); - - /// Returns the fields of `Type`, limited to the set of fields modeled by this - /// context. - llvm::DenseSet getReferencedFields(QualType Type); + void addModeledFields(const FieldSet &Fields); /// Adds all constraints of the flow condition identified by `Token` and all /// of its transitive dependencies to `Constraints`. `VisitedTokens` is used @@ -257,7 +261,7 @@ class DataflowAnalysisContext { llvm::DenseMap FunctionContexts; // Fields modeled by environments covered by this context. - llvm::DenseSet ModeledFields; + FieldSet ModeledFields; std::unique_ptr LogOwner; // If created via flags. }; diff --git a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp index a807ef8209be85..b0c1014e3c975e 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp @@ -40,31 +40,28 @@ static llvm::cl::opt DataflowLog( namespace clang { namespace dataflow { -void DataflowAnalysisContext::addModeledFields( -const llvm::DenseSet &Fields) { - llvm::set_union(ModeledFields, Fields); +FieldSet DataflowAnalysisContext::getModeledFields(QualType Type) { + // During context-sensitive analysis, a struct may be allocated in one + // function, but its field accessed in a function lower in the stack than + // the allocation. Since we only collect fields used in the function where + // the allocation occurs, we can't apply that filter when performing + // context-sensitive analysis. But, this only applies to storage locations, + // since field access it not allowed to fail. In contrast, field *values* + // don't need this allowance, since the API allows for uninitialized fields. + if (Opts.ContextSensitiveOpts) +return getObjectFields(Type); + + return llvm::set_intersection(getObjectFields(Type), ModeledFields); } -llvm::DenseSet -DataflowAnalysis
[clang] f653d14 - [clang][dataflow] Various refactorings to UncheckedOptionalAccessModel.
Author: Martin Braenne Date: 2023-07-10T06:45:55Z New Revision: f653d14065a362c98114082c4e9a3b1ede7a90f5 URL: https://github.com/llvm/llvm-project/commit/f653d14065a362c98114082c4e9a3b1ede7a90f5 DIFF: https://github.com/llvm/llvm-project/commit/f653d14065a362c98114082c4e9a3b1ede7a90f5.diff LOG: [clang][dataflow] Various refactorings to UncheckedOptionalAccessModel. These are intended to ease an upcoming change that will eliminate the duplication between `AggregateStorageLocation` and `StructValue` (see https://discourse.llvm.org/t/70086 for details), but many of the changes also have value in their own right. Depends On D154586 Reviewed By: ymandel, gribozavr2 Differential Revision: https://reviews.llvm.org/D154597 Added: Modified: clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp index a239d54674e96c..91aa9d11e751cd 100644 --- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp +++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp @@ -255,12 +255,22 @@ void setHasValue(Value &OptionalVal, BoolValue &HasValueVal) { /// Creates a symbolic value for an `optional` value using `HasValueVal` as the /// symbolic value of its "has_value" property. -StructValue &createOptionalValue(Environment &Env, BoolValue &HasValueVal) { +StructValue &createOptionalValue(BoolValue &HasValueVal, Environment &Env) { auto &OptionalVal = Env.create(); setHasValue(OptionalVal, HasValueVal); return OptionalVal; } +/// Creates a symbolic value for an `optional` value at an existing storage +/// location. Uses `HasValueVal` as the symbolic value of the "has_value" +/// property. +StructValue &createOptionalValue(AggregateStorageLocation &Loc, + BoolValue &HasValueVal, Environment &Env) { + StructValue &OptionalVal = createOptionalValue(HasValueVal, Env); + Env.setValue(Loc, OptionalVal); + return OptionalVal; +} + /// Returns the symbolic value that represents the "has_value" property of the /// optional value `OptionalVal`. Returns null if `OptionalVal` is null. BoolValue *getHasValue(Environment &Env, Value *OptionalVal) { @@ -422,15 +432,6 @@ bool isNonEmptyOptional(const Value &OptionalVal, const Environment &Env) { return HasValueVal != nullptr && Env.flowConditionImplies(*HasValueVal); } -StorageLocation *maybeSkipPointer(StorageLocation *Loc, - const Environment &Env) { - if (Loc == nullptr) -return nullptr; - if (auto *Val = dyn_cast_or_null(Env.getValue(*Loc))) -return &Val->getPointeeLoc(); - return Loc; -} - Value *getValueBehindPossiblePointer(const Expr &E, const Environment &Env) { Value *Val = Env.getValue(E, SkipPast::Reference); if (auto *PointerVal = dyn_cast_or_null(Val)) @@ -467,7 +468,7 @@ void transferMakeOptionalCall(const CallExpr *E, auto &Loc = State.Env.createStorageLocation(*E); State.Env.setStorageLocation(*E, Loc); State.Env.setValue( - Loc, createOptionalValue(State.Env, State.Env.getBoolLiteralValue(true))); + Loc, createOptionalValue(State.Env.getBoolLiteralValue(true), State.Env)); } void transferOptionalHasValueCall(const CXXMemberCallExpr *CallExpr, @@ -544,15 +545,12 @@ void transferCallReturningOptional(const CallExpr *E, auto &Loc = State.Env.createStorageLocation(*E); State.Env.setStorageLocation(*E, Loc); State.Env.setValue( - Loc, createOptionalValue(State.Env, State.Env.makeAtomicBoolValue())); + Loc, createOptionalValue(State.Env.makeAtomicBoolValue(), State.Env)); } -void assignOptionalValue(const Expr &E, Environment &Env, - BoolValue &HasValueVal) { - if (auto *OptionalLoc = maybeSkipPointer( - Env.getStorageLocation(E, SkipPast::Reference), Env)) { -Env.setValue(*OptionalLoc, createOptionalValue(Env, HasValueVal)); - } +void constructOptionalValue(const Expr &E, Environment &Env, +BoolValue &HasValueVal) { + Env.setValueStrict(E, createOptionalValue(HasValueVal, Env)); } /// Returns a symbolic value for the "has_value" property of an `optional` @@ -590,25 +588,23 @@ void transferValueOrConversionConstructor( LatticeTransferState &State) { assert(E->getNumArgs() > 0); - assignOptionalValue(*E, State.Env, - valueOrConversionHasValue(*E->getConstructor(), -*E->getArg(0), MatchRes, -State)); + constructOptionalValue(*E, State.Env, + valueOrConversionHasValue(*E->getConstructor(), + *E->getArg(0), MatchRes, +
[clang] 8bc13c8 - [clang][dataflow] Add `AnalysisInputs::withSolverFactory()`.
Author: Martin Braenne Date: 2023-07-10T13:43:13Z New Revision: 8bc13c884727f0b9be876303d654dd1eda300dc3 URL: https://github.com/llvm/llvm-project/commit/8bc13c884727f0b9be876303d654dd1eda300dc3 DIFF: https://github.com/llvm/llvm-project/commit/8bc13c884727f0b9be876303d654dd1eda300dc3.diff LOG: [clang][dataflow] Add `AnalysisInputs::withSolverFactory()`. Reviewed By: sammccall Differential Revision: https://reviews.llvm.org/D154833 Added: Modified: clang/unittests/Analysis/FlowSensitive/TestingSupport.h Removed: diff --git a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h index 93991d87d77f20..1568fc9a200e47 100644 --- a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h +++ b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h @@ -143,6 +143,12 @@ template struct AnalysisInputs { BuiltinOptions = std::move(Options); return std::move(*this); } + AnalysisInputs && + withSolverFactory(std::function()> Factory) && { +assert(Factory); +SolverFactory = std::move(Factory); +return std::move(*this); + } /// Required. Input code that is analyzed. llvm::StringRef Code; @@ -170,6 +176,10 @@ template struct AnalysisInputs { tooling::FileContentMappings ASTBuildVirtualMappedFiles = {}; /// Configuration options for the built-in model. DataflowAnalysisContext::Options BuiltinOptions; + /// SAT solver factory. + std::function()> SolverFactory = [] { +return std::make_unique(); + }; }; /// Returns assertions based on annotations that are present after statements in @@ -248,7 +258,7 @@ checkDataflow(AnalysisInputs AI, auto &CFCtx = *MaybeCFCtx; // Initialize states for running dataflow analysis. -DataflowAnalysisContext DACtx(std::make_unique(), +DataflowAnalysisContext DACtx(AI.SolverFactory(), {/*Opts=*/AI.BuiltinOptions}); Environment InitEnv(DACtx, *Target); auto Analysis = AI.MakeAnalysis(Context, InitEnv); ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] e53da3e - [clang][dataflow][NFC] Expand a comment.
Author: Martin Braenne Date: 2023-07-11T06:32:08Z New Revision: e53da3eab42e6efd448c1c60c14668e1eb3d907c URL: https://github.com/llvm/llvm-project/commit/e53da3eab42e6efd448c1c60c14668e1eb3d907c DIFF: https://github.com/llvm/llvm-project/commit/e53da3eab42e6efd448c1c60c14668e1eb3d907c.diff LOG: [clang][dataflow][NFC] Expand a comment. Reviewed By: sammccall Differential Revision: https://reviews.llvm.org/D154834 Added: Modified: clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index c3de50894c9ede..73e20705cff501 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -123,6 +123,9 @@ static Value *mergeDistinctValues(QualType Type, Value &Val1, // returns false to avoid storing unneeded values in `DACtx`. // FIXME: Creating the value based on the type alone creates misshapen values // for lvalues, since the type does not reflect the need for `ReferenceValue`. + // This issue will be resolved when `ReferenceValue` is eliminated as part + // of the ongoing migration to strict handling of value categories (see + // https://discourse.llvm.org/t/70086 for details). if (Value *MergedVal = MergedEnv.createValue(Type)) if (Model.merge(Type, Val1, Env1, Val2, Env2, *MergedVal, MergedEnv)) return MergedVal; ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 2902ea3 - [clang][dataflow] Introduce `getFieldValue()` test helpers.
Author: Martin Braenne Date: 2023-07-12T04:52:23Z New Revision: 2902ea3d817bf381817ff76228c3212f4dc87d47 URL: https://github.com/llvm/llvm-project/commit/2902ea3d817bf381817ff76228c3212f4dc87d47 DIFF: https://github.com/llvm/llvm-project/commit/2902ea3d817bf381817ff76228c3212f4dc87d47.diff LOG: [clang][dataflow] Introduce `getFieldValue()` test helpers. These insulate tests against changes to the `getChild()` functions of `AggregateStorageLocation` and `StructValue` that will happen as part of the migration to strict handling of value categories (see https://discourse.llvm.org/t/70086 for details): - `AggregateStorageLocation::getChild()` will soon return a `StorageLocation *` instead of a `StorageLocation &`. When this happens, `getFieldValue()` will be changed to return null if `AggregateStorageLocation::getChild()` returns null; test code will not need to change as it should already be checking whether the return value of `getFieldValue()` is null. - `StructValue::getChild()` will soon return a `StorageLocation *` instead of a `Value *`. When this happens, `getFieldValue()` will be changed to look up the `Value *` in the `Environment`. Again, test code will not need to change. The test helpers will continue to serve a useful purpose once the API changes are complete, so the intent is to leave them in place. This patch changes DataflowEnvironmentTest.cpp and RecordOpsTest.cpp to use the test helpers. TransferTest.cpp will be changed in an upcoming patch to help keep patch sizes manageable for review. Depends On D154934 Reviewed By: ymandel, xazax.hun, gribozavr2 Differential Revision: https://reviews.llvm.org/D154935 Added: Modified: clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp clang/unittests/Analysis/FlowSensitive/RecordOpsTest.cpp clang/unittests/Analysis/FlowSensitive/TestingSupport.h Removed: diff --git a/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp b/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp index 1c78dd380c7742..17c0f7b16c1c71 100644 --- a/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp @@ -7,6 +7,7 @@ //===--===// #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" +#include "TestingSupport.h" #include "clang/AST/DeclCXX.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" @@ -23,6 +24,7 @@ namespace { using namespace clang; using namespace dataflow; +using ::clang::dataflow::test::getFieldValue; using ::testing::ElementsAre; using ::testing::NotNull; using ::testing::Pair; @@ -89,14 +91,9 @@ TEST_F(EnvironmentTest, CreateValueRecursiveType) { // Verify that the struct and the field (`R`) with first appearance of the // type is created successfully. Environment Env(DAContext, *Fun); - Value *Val = Env.createValue(Ty); - ASSERT_NE(Val, nullptr); - StructValue *SVal = clang::dyn_cast(Val); - ASSERT_NE(SVal, nullptr); - Val = SVal->getChild(*R); - ASSERT_NE(Val, nullptr); - PointerValue *PV = clang::dyn_cast(Val); - EXPECT_NE(PV, nullptr); + StructValue *SVal = cast(Env.createValue(Ty)); + PointerValue *PV = cast_or_null(getFieldValue(SVal, *R, Env)); + EXPECT_THAT(PV, NotNull()); } TEST_F(EnvironmentTest, InitGlobalVarsFun) { @@ -175,8 +172,7 @@ TEST_F(EnvironmentTest, IncludeFieldsFromDefaultInitializers) { // constructor, even though it is not referenced directly in the constructor. Environment Env(DAContext, *Constructor); auto *Val = cast(Env.createValue(QTy)); - ASSERT_THAT(Val, NotNull()); - EXPECT_THAT(Val->getChild(*XDecl), NotNull()); + EXPECT_THAT(getFieldValue(Val, *XDecl, Env), NotNull()); } TEST_F(EnvironmentTest, InitGlobalVarsFieldFun) { @@ -221,8 +217,7 @@ TEST_F(EnvironmentTest, InitGlobalVarsFieldFun) { const auto *GlobalLoc = cast(Env.getStorageLocation(*GlobalDecl)); const auto *GlobalVal = cast(Env.getValue(*GlobalLoc)); - const auto *BarVal = GlobalVal->getChild(*BarDecl); - ASSERT_THAT(BarVal, NotNull()); + auto *BarVal = getFieldValue(GlobalVal, *BarDecl, Env); EXPECT_TRUE(isa(BarVal)); } diff --git a/clang/unittests/Analysis/FlowSensitive/RecordOpsTest.cpp b/clang/unittests/Analysis/FlowSensitive/RecordOpsTest.cpp index 1f5fce1f2dd467..dc81e9594b6914 100644 --- a/clang/unittests/Analysis/FlowSensitive/RecordOpsTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/RecordOpsTest.cpp @@ -63,12 +63,12 @@ TEST(RecordOpsTest, CopyRecord) { auto &Inner1 = cast(S1.getChild(*InnerDecl)); auto &Inner2 = cast(S2.getChild(*InnerDecl)); -EXPECT_NE(Env.getValue(S1.getChild(*OuterIntDecl)), - Env.getValue(S2.getChild(*OuterIntDecl))); +EXPECT
[clang] 103a0fc - [clang][dataflow] Use `getFieldValue()` in TransferTest.cpp.
Author: Martin Braenne Date: 2023-07-12T04:52:25Z New Revision: 103a0fc0846050dd671e6485ab52491042f905c6 URL: https://github.com/llvm/llvm-project/commit/103a0fc0846050dd671e6485ab52491042f905c6 DIFF: https://github.com/llvm/llvm-project/commit/103a0fc0846050dd671e6485ab52491042f905c6.diff LOG: [clang][dataflow] Use `getFieldValue()` in TransferTest.cpp. For context, see https://reviews.llvm.org/D154935. Depends On D154935 Reviewed By: ymandel, xazax.hun Differential Revision: https://reviews.llvm.org/D154949 Added: Modified: clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index baadea57e43751..3ae3106bca4673 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -262,7 +262,8 @@ TEST(TransferTest, StructVarDecl) { cast(&FooLoc->getChild(*BarDecl)); const auto *FooVal = cast(Env.getValue(*FooLoc)); -const auto *BarVal = cast(FooVal->getChild(*BarDecl)); +const auto *BarVal = +cast(getFieldValue(FooVal, *BarDecl, Env)); EXPECT_EQ(Env.getValue(*BarLoc), BarVal); }); } @@ -310,7 +311,8 @@ TEST(TransferTest, StructVarDeclWithInit) { cast(&FooLoc->getChild(*BarDecl)); const auto *FooVal = cast(Env.getValue(*FooLoc)); -const auto *BarVal = cast(FooVal->getChild(*BarDecl)); +const auto *BarVal = +cast(getFieldValue(FooVal, *BarDecl, Env)); EXPECT_EQ(Env.getValue(*BarLoc), BarVal); }); } @@ -357,7 +359,8 @@ TEST(TransferTest, ClassVarDecl) { cast(&FooLoc->getChild(*BarDecl)); const auto *FooVal = cast(Env.getValue(*FooLoc)); -const auto *BarVal = cast(FooVal->getChild(*BarDecl)); +const auto *BarVal = +cast(getFieldValue(FooVal, *BarDecl, Env)); EXPECT_EQ(Env.getValue(*BarLoc), BarVal); }); } @@ -470,37 +473,37 @@ TEST(TransferTest, SelfReferentialReferenceVarDecl) { ASSERT_THAT(BazRefDecl, NotNull()); ASSERT_THAT(BazPtrDecl, NotNull()); -const auto *FooLoc = -cast(Env.getStorageLocation(*FooDecl)); -const auto *FooReferentVal = cast(Env.getValue(*FooLoc)); +const auto &FooLoc = +*cast(Env.getStorageLocation(*FooDecl)); +const auto &FooReferentVal = *cast(Env.getValue(FooLoc)); -const auto *BarVal = -cast(FooReferentVal->getChild(*BarDecl)); -const auto *BarReferentVal = -cast(Env.getValue(BarVal->getReferentLoc())); +const auto &BarVal = +*cast(FooReferentVal.getChild(*BarDecl)); +const auto &BarReferentVal = +*cast(Env.getValue(BarVal.getReferentLoc())); -const auto *FooRefVal = -cast(BarReferentVal->getChild(*FooRefDecl)); +const auto &FooRefVal = +*cast(getFieldValue(&BarReferentVal, *FooRefDecl, Env)); const auto &FooReferentLoc = -cast(FooRefVal->getReferentLoc()); +cast(FooRefVal.getReferentLoc()); EXPECT_THAT(Env.getValue(FooReferentLoc), NotNull()); -EXPECT_THAT(Env.getValue(FooReferentLoc.getChild(*BarDecl)), IsNull()); +EXPECT_THAT(getFieldValue(&FooReferentLoc, *BarDecl, Env), IsNull()); -const auto *FooPtrVal = -cast(BarReferentVal->getChild(*FooPtrDecl)); +const auto &FooPtrVal = +*cast(getFieldValue(&BarReferentVal, *FooPtrDecl, Env)); const auto &FooPtrPointeeLoc = -cast(FooPtrVal->getPointeeLoc()); +cast(FooPtrVal.getPointeeLoc()); EXPECT_THAT(Env.getValue(FooPtrPointeeLoc), NotNull()); -EXPECT_THAT(Env.getValue(FooPtrPointeeLoc.getChild(*BarDecl)), IsNull()); +EXPECT_THAT(getFieldValue(&FooPtrPointeeLoc, *BarDecl, Env), IsNull()); -const auto *BazRefVal = -cast(BarReferentVal->getChild(*BazRefDecl)); -const StorageLocation &BazReferentLoc = BazRefVal->getReferentLoc(); +const auto &BazRefVal = +*cast(getFieldValue(&BarReferentVal, *BazRefDecl, Env)); +const StorageLocation &BazReferentLoc = BazRefVal.getReferentLoc(); EXPECT_THAT(Env.getValue(BazReferentLoc), NotNull()); -const auto *BazPtrVal = -cast(BarReferentVal->getChild(*BazPtrDecl)); -const StorageLocation &BazPtrPointeeLoc = BazPtrVal->getPointeeLoc(); +const auto &BazPtrVal = +*cast(getFieldValue(&BarReferentVal, *BazPtrDecl, Env)); +const StorageLocation &BazPtrPointeeLoc = BazPtrVal.getPointeeLoc(); EXPECT_THAT(Env.getValue(BazPtrPointeeLoc), NotNull()); }); } @@ -630,35 +633,36 @@ TEST(TransferTest, SelfReferentialPointerVarDecl) { ASSERT_THAT(BazRefDecl, NotNull()); ASSERT_THAT(BazPtrDecl, NotNull()); -const auto *FooLoc = -cast(Env.getStorageLocation(*FooDecl)); -
[clang] 0014aab - [clang][dataflow] Use `IntegerValue` instead of `StructValue` in `ValueTest`.
Author: Martin Braenne Date: 2023-07-12T04:52:22Z New Revision: 0014aab2d5882525c23130108e17fbbb5a2120f1 URL: https://github.com/llvm/llvm-project/commit/0014aab2d5882525c23130108e17fbbb5a2120f1 DIFF: https://github.com/llvm/llvm-project/commit/0014aab2d5882525c23130108e17fbbb5a2120f1.diff LOG: [clang][dataflow] Use `IntegerValue` instead of `StructValue` in `ValueTest`. Soon, it will no longer be possible to default-construct `StructValue`. For details, see https://discourse.llvm.org/t/70086. For completeness, also add a test that `areEquivalentValues()` on different `IntegerValue`s returns false. Reviewed By: xazax.hun, gribozavr2 Differential Revision: https://reviews.llvm.org/D154934 Added: Modified: clang/unittests/Analysis/FlowSensitive/ValueTest.cpp Removed: diff --git a/clang/unittests/Analysis/FlowSensitive/ValueTest.cpp b/clang/unittests/Analysis/FlowSensitive/ValueTest.cpp index 02f3adeaeda756..19ea7a04928f28 100644 --- a/clang/unittests/Analysis/FlowSensitive/ValueTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/ValueTest.cpp @@ -19,10 +19,16 @@ using namespace clang; using namespace dataflow; TEST(ValueTest, EquivalenceReflexive) { - StructValue V; + IntegerValue V; EXPECT_TRUE(areEquivalentValues(V, V)); } +TEST(ValueTest, DifferentIntegerValuesNotEquivalent) { + IntegerValue V1; + IntegerValue V2; + EXPECT_FALSE(areEquivalentValues(V1, V2)); +} + TEST(ValueTest, AliasedReferencesEquivalent) { auto L = ScalarStorageLocation(QualType()); ReferenceValue V1(L); ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 1e9b4fc - [clang][dataflow] Various refactorings in TypeErasedDataflowAnalysisTest.cpp
Author: Martin Braenne Date: 2023-07-12T04:52:27Z New Revision: 1e9b4fc1dcf27ae43477efe0329f738e4419871b URL: https://github.com/llvm/llvm-project/commit/1e9b4fc1dcf27ae43477efe0329f738e4419871b DIFF: https://github.com/llvm/llvm-project/commit/1e9b4fc1dcf27ae43477efe0329f738e4419871b.diff LOG: [clang][dataflow] Various refactorings in TypeErasedDataflowAnalysisTest.cpp These simplify the code in their own right, but they are also useful in that they minimize the number of changes that will need to be made when then API of `AggregateStorageLocation` and `StructValue` changes as part of the migration to strict handling of value categories (see https://discourse.llvm.org/t/70086). Depends On D154949 Reviewed By: xazax.hun, gribozavr2 Differential Revision: https://reviews.llvm.org/D154952 Added: Modified: clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp Removed: diff --git a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp index 473750ad7a6cb4..d811aed8fddd99 100644 --- a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp @@ -370,6 +370,13 @@ TEST_F(NoreturnDestructorTest, ConditionalOperatorNestedBranchReturns) { // FIXME: Called functions at point `p` should contain only "foo". } +StructValue &createNewStructValue(AggregateStorageLocation &Loc, + Environment &Env) { + auto &Val = *cast(Env.createValue(Loc.getType())); + Env.setValue(Loc, Val); + return Val; +} + // Models an analysis that uses flow conditions. class SpecialBoolAnalysis final : public DataflowAnalysis { @@ -390,23 +397,18 @@ class SpecialBoolAnalysis final if (const auto *E = selectFirst( "call", match(cxxConstructExpr(HasSpecialBoolType).bind("call"), *S, getASTContext( { - auto &ConstructorVal = *Env.createValue(E->getType()); - ConstructorVal.setProperty("is_set", Env.getBoolLiteralValue(false)); - Env.setValue(*Env.getStorageLocation(*E, SkipPast::None), ConstructorVal); + cast(Env.getValueStrict(*E)) + ->setProperty("is_set", Env.getBoolLiteralValue(false)); } else if (const auto *E = selectFirst( "call", match(cxxMemberCallExpr(callee(cxxMethodDecl(ofClass( SpecialBoolRecordDecl .bind("call"), *S, getASTContext( { - auto *Object = E->getImplicitObjectArgument(); - assert(Object != nullptr); - - auto *ObjectLoc = getImplicitObjectLocation(*E, Env); - assert(ObjectLoc != nullptr); + auto &ObjectLoc = + *cast(getImplicitObjectLocation(*E, Env)); - auto &ConstructorVal = *Env.createValue(Object->getType()); - ConstructorVal.setProperty("is_set", Env.getBoolLiteralValue(true)); - Env.setValue(*ObjectLoc, ConstructorVal); + createNewStructValue(ObjectLoc, Env) + .setProperty("is_set", Env.getBoolLiteralValue(true)); } } @@ -551,21 +553,19 @@ class OptionalIntAnalysis final *S, getASTContext()); if (const auto *E = selectFirst( "construct", Matches)) { - auto &ConstructorVal = *Env.createValue(E->getType()); - ConstructorVal.setProperty("has_value", Env.getBoolLiteralValue(false)); - Env.setValue(*Env.getStorageLocation(*E, SkipPast::None), ConstructorVal); + cast(Env.getValueStrict(*E)) + ->setProperty("has_value", Env.getBoolLiteralValue(false)); } else if (const auto *E = selectFirst("operator", Matches)) { assert(E->getNumArgs() > 0); auto *Object = E->getArg(0); assert(Object != nullptr); - auto *ObjectLoc = Env.getStorageLocation(*Object, SkipPast::Reference); - assert(ObjectLoc != nullptr); + auto &ObjectLoc = *cast( + Env.getStorageLocation(*Object, SkipPast::Reference)); - auto &ConstructorVal = *Env.createValue(Object->getType()); - ConstructorVal.setProperty("has_value", Env.getBoolLiteralValue(true)); - Env.setValue(*ObjectLoc, ConstructorVal); + createNewStructValue(ObjectLoc, Env) + .setProperty("has_value", Env.getBoolLiteralValue(true)); } } @@ -1227,9 +1227,7 @@ class TopAnalysis final : public DataflowAnalysis { match(callExpr(callee(functionDecl(hasName("makeTop".bind("top"), *S, getASTContext()); if (const auto *E = selectFirst("top", Matches)) { - auto &Loc = Env.createStorageLocation(*E); - Env.setValue(Loc, Env.makeTopBoolValue()); - Env.setStorageLocation(*E, Loc); + Env.setValueStrict(*E, Env.ma
[clang] b47bdcb - [clang][dataflow] Include fields initialized in an `InitListExpr` in `getModeledFields()`.
Author: Martin Braenne Date: 2023-07-12T04:52:29Z New Revision: b47bdcbc7207aac617d3c35dfc029f79b0a46fd8 URL: https://github.com/llvm/llvm-project/commit/b47bdcbc7207aac617d3c35dfc029f79b0a46fd8 DIFF: https://github.com/llvm/llvm-project/commit/b47bdcbc7207aac617d3c35dfc029f79b0a46fd8.diff LOG: [clang][dataflow] Include fields initialized in an `InitListExpr` in `getModeledFields()`. Previously, we were including these fields only in the specific instance that was initialized by the `InitListExpr`, but not in other instances of the same type. This is inconsistent and error-prone. Depends On D154952 Reviewed By: xazax.hun, gribozavr2 Differential Revision: https://reviews.llvm.org/D154961 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index 7c1d01ce816e2b..5bd2e5518a5463 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -644,6 +644,10 @@ getImplicitObjectLocation(const CXXMemberCallExpr &MCE, const Environment &Env); AggregateStorageLocation *getBaseObjectLocation(const MemberExpr &ME, const Environment &Env); +/// Returns the fields of `RD` that are initialized by an `InitListExpr`, in the +/// order in which they appear in `InitListExpr::inits()`. +std::vector getFieldsForInitListExpr(const RecordDecl *RD); + } // namespace dataflow } // namespace clang diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index 73e20705cff501..9b1fca41e911cc 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -215,6 +215,10 @@ getFieldsGlobalsAndFuncs(const Stmt &S, FieldSet &Fields, insertIfFunction(*VD, Funcs); if (const auto *FD = dyn_cast(VD)) Fields.insert(FD); + } else if (auto *InitList = dyn_cast(&S)) { +if (RecordDecl *RD = InitList->getType()->getAsRecordDecl()) + for (const auto *FD : getFieldsForInitListExpr(RD)) +Fields.insert(FD); } } @@ -958,5 +962,17 @@ AggregateStorageLocation *getBaseObjectLocation(const MemberExpr &ME, return cast(Loc); } +std::vector getFieldsForInitListExpr(const RecordDecl *RD) { + // Unnamed bitfields are only used for padding and do not appear in + // `InitListExpr`'s inits. However, those fields do appear in `RecordDecl`'s + // field list, and we thus need to remove them before mapping inits to + // fields to avoid mapping inits to the wrongs fields. + std::vector Fields; + llvm::copy_if( + RD->fields(), std::back_inserter(Fields), + [](const FieldDecl *Field) { return !Field->isUnnamedBitfield(); }); + return Fields; +} + } // namespace dataflow } // namespace clang diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp index ac971f69150f1e..e1a2606de81033 100644 --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -715,14 +715,8 @@ class TransferVisitor : public ConstStmtVisitor { Env.setValue(Loc, *Val); if (Type->isStructureOrClassType()) { - // Unnamed bitfields are only used for padding and are not appearing in - // `InitListExpr`'s inits. However, those fields do appear in RecordDecl's - // field list, and we thus need to remove them before mapping inits to - // fields to avoid mapping inits to the wrongs fields. - std::vector Fields; - llvm::copy_if( - Type->getAsRecordDecl()->fields(), std::back_inserter(Fields), - [](const FieldDecl *Field) { return !Field->isUnnamedBitfield(); }); + std::vector Fields = + getFieldsForInitListExpr(Type->getAsRecordDecl()); for (auto It : llvm::zip(Fields, S->inits())) { const FieldDecl *Field = std::get<0>(It); assert(Field != nullptr); diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index 3ae3106bca4673..254226fd6d3ee9 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -2833,6 +2833,7 @@ TEST(TransferTest, AggregateInitialization) { void target(int BarArg, int FooArg, int QuxArg) { B Quux{BarArg, {FooArg}, QuxArg}; + B OtherB; /*[[p]]*/ } )"; @@ -2849,6 +2850,7 @@ TEST(TransferTest, Ag
[clang] bd9b57d - [clang][dataflow] Fix initializing a reference field with an `InitListExpr`.
Author: Martin Braenne Date: 2023-07-12T04:52:30Z New Revision: bd9b57de4ff7c65be0d69179232ba2d5fe832195 URL: https://github.com/llvm/llvm-project/commit/bd9b57de4ff7c65be0d69179232ba2d5fe832195 DIFF: https://github.com/llvm/llvm-project/commit/bd9b57de4ff7c65be0d69179232ba2d5fe832195.diff LOG: [clang][dataflow] Fix initializing a reference field with an `InitListExpr`. I added a test for this as the ongoing migration to strict handling of value categories (see https://discourse.llvm.org/t/70086) will change the code that handles this case. It turns out we already didn't handle this correctly, so I fixed the existing implementation. Depends On D154961 Reviewed By: xazax.hun Differential Revision: https://reviews.llvm.org/D154965 Added: Modified: clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp index e1a2606de81033..4c97e81184bba3 100644 --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -717,14 +717,15 @@ class TransferVisitor : public ConstStmtVisitor { if (Type->isStructureOrClassType()) { std::vector Fields = getFieldsForInitListExpr(Type->getAsRecordDecl()); - for (auto It : llvm::zip(Fields, S->inits())) { -const FieldDecl *Field = std::get<0>(It); + for (auto [Field, Init] : llvm::zip(Fields, S->inits())) { assert(Field != nullptr); - -const Expr *Init = std::get<1>(It); assert(Init != nullptr); -if (Value *InitVal = Env.getValue(*Init, SkipPast::None)) +if (Field->getType()->isReferenceType()) { + if (StorageLocation *Loc = Env.getStorageLocationStrict(*Init)) +cast(Val)->setChild(*Field, + Env.create(*Loc)); +} else if (Value *InitVal = Env.getValue(*Init, SkipPast::None)) cast(Val)->setChild(*Field, *InitVal); } } diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index 254226fd6d3ee9..a89ff8e7bc5ab5 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -2912,6 +2912,34 @@ TEST(TransferTest, AggregateInitialization) { } } +TEST(TransferTest, AggregateInitializationReferenceField) { + std::string Code = R"( +struct S { + int &RefField; +}; + +void target(int i) { + S s = { i }; + /*[[p]]*/ +} + )"; + runDataflow( + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) { +const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); + +const ValueDecl *RefFieldDecl = findValueDecl(ASTCtx, "RefField"); + +auto &ILoc = getLocForDecl(ASTCtx, Env, "i"); +auto &SLoc = getLocForDecl(ASTCtx, Env, "s"); + +auto &RefValue = +*cast(getFieldValue(&SLoc, *RefFieldDecl, Env)); +EXPECT_EQ(&RefValue.getReferentLoc(), &ILoc); + }); +} + TEST(TransferTest, AssignToUnionMember) { std::string Code = R"( union A { ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 4782597 - [clang][dataflow] Add a test for not explicitly initialized fields in aggregate initialization.
Author: Martin Braenne Date: 2023-07-17T07:26:08Z New Revision: 4782597e3cd1b26cf8bd437e36fd6320f55d3d89 URL: https://github.com/llvm/llvm-project/commit/4782597e3cd1b26cf8bd437e36fd6320f55d3d89 DIFF: https://github.com/llvm/llvm-project/commit/4782597e3cd1b26cf8bd437e36fd6320f55d3d89.diff LOG: [clang][dataflow] Add a test for not explicitly initialized fields in aggregate initialization. Reviewed By: ymandel Differential Revision: https://reviews.llvm.org/D155074 Added: Modified: clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index 5a5540cbaee3dc..e2800452ab6bdb 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -2944,6 +2944,39 @@ TEST(TransferTest, AggregateInitializationReferenceField) { }); } +TEST(TransferTest, AggregateInitialization_NotExplicitlyInitializedField) { + std::string Code = R"( +struct S { + int i1; + int i2; +}; + +void target(int i) { + S s = { i }; + /*[[p]]*/ +} + )"; + runDataflow( + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) { +const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); + +const ValueDecl *I1FieldDecl = findValueDecl(ASTCtx, "i1"); +const ValueDecl *I2FieldDecl = findValueDecl(ASTCtx, "i2"); + +auto &SLoc = getLocForDecl(ASTCtx, Env, "s"); + +auto &IValue = getValueForDecl(ASTCtx, Env, "i"); +auto &I1Value = +*cast(getFieldValue(&SLoc, *I1FieldDecl, Env)); +EXPECT_EQ(&I1Value, &IValue); +auto &I2Value = +*cast(getFieldValue(&SLoc, *I2FieldDecl, Env)); +EXPECT_NE(&I2Value, &IValue); + }); +} + TEST(TransferTest, AssignToUnionMember) { std::string Code = R"( union A { ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 243a79c - [clang][dataflow] Simplify implementation of `transferStdForwardCall()` in optional check.
Author: Martin Braenne Date: 2023-07-17T07:26:11Z New Revision: 243a79ca01f8142a8d8c9873ba58fefdafa48745 URL: https://github.com/llvm/llvm-project/commit/243a79ca01f8142a8d8c9873ba58fefdafa48745 DIFF: https://github.com/llvm/llvm-project/commit/243a79ca01f8142a8d8c9873ba58fefdafa48745.diff LOG: [clang][dataflow] Simplify implementation of `transferStdForwardCall()` in optional check. The argument and return value of `std::forward` is always a reference, so we can simply forward the storage location. Depends On D155075 Reviewed By: ymandel, gribozavr2, xazax.hun Differential Revision: https://reviews.llvm.org/D155202 Added: Modified: clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp index 7f516984094648..a39aa2240c4fc6 100644 --- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp +++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp @@ -683,25 +683,8 @@ void transferStdForwardCall(const CallExpr *E, const MatchFinder::MatchResult &, LatticeTransferState &State) { assert(E->getNumArgs() == 1); - StorageLocation *LocRet = State.Env.getStorageLocation(*E, SkipPast::None); - if (LocRet != nullptr) -return; - - StorageLocation *LocArg = - State.Env.getStorageLocation(*E->getArg(0), SkipPast::Reference); - - if (LocArg == nullptr) -return; - - Value *ValArg = State.Env.getValue(*LocArg); - if (ValArg == nullptr) -ValArg = &createOptionalValue(State.Env.makeAtomicBoolValue(), State.Env); - - // Create a new storage location - LocRet = &State.Env.createStorageLocation(*E); - State.Env.setStorageLocation(*E, *LocRet); - - State.Env.setValue(*LocRet, *ValArg); + if (auto *Loc = State.Env.getStorageLocationStrict(*E->getArg(0))) +State.Env.setStorageLocationStrict(*E, *Loc); } const Formula &evaluateEquality(Arena &A, const Formula &EqVal, ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] d17f455 - [clang][dataflow] Add `refreshStructValue()`.
Author: Martin Braenne Date: 2023-07-17T07:26:13Z New Revision: d17f455a6348806c73641e742af08b0a974e13d5 URL: https://github.com/llvm/llvm-project/commit/d17f455a6348806c73641e742af08b0a974e13d5 DIFF: https://github.com/llvm/llvm-project/commit/d17f455a6348806c73641e742af08b0a974e13d5.diff LOG: [clang][dataflow] Add `refreshStructValue()`. Besides being a useful abstraction, this function will help insulate existing clients of the framework from upcoming changes to the API of `StructValue` and `AggregateStorageLocation`. Depends On D155202 Reviewed By: ymandel, xazax.hun Differential Revision: https://reviews.llvm.org/D155204 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index dc82ccea4a27d4..9d99b6771f71e1 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -389,6 +389,12 @@ class Environment { /// necessary storage locations and values for indirections until it finds a /// non-pointer/non-reference type. /// + /// If `Type` is one of the following types, this function will always return + /// a non-null pointer: + /// - `bool` + /// - Any integer type + /// - Any class, struct, or union type + /// /// Requirements: /// /// `Type` must not be null. @@ -692,6 +698,24 @@ AggregateStorageLocation *getBaseObjectLocation(const MemberExpr &ME, /// order in which they appear in `InitListExpr::inits()`. std::vector getFieldsForInitListExpr(const RecordDecl *RD); +/// Associates a new `StructValue` with `Loc` and returns the new value. +/// It is not defined whether the field values remain the same or not. +/// +/// This function is primarily intended for use by checks that set custom +/// properties on `StructValue`s to model the state of these values. Such checks +/// should avoid modifying the properties of an existing `StructValue` because +/// these changes would be visible to other `Environment`s that share the same +/// `StructValue`. Instead, call `refreshStructValue()`, then set the properties +/// on the new `StructValue` that it returns. Typical usage: +/// +/// refreshStructValue(Loc, Env).setProperty("my_prop", MyPropValue); +StructValue &refreshStructValue(AggregateStorageLocation &Loc, +Environment &Env); + +/// Associates a new `StructValue` with `Expr` and returns the new value. +/// See also documentation for the overload above. +StructValue &refreshStructValue(const Expr &Expr, Environment &Env); + } // namespace dataflow } // namespace clang diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index fdd6b5959cd722..5d301b815d38e0 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -987,5 +987,30 @@ std::vector getFieldsForInitListExpr(const RecordDecl *RD) { return Fields; } +StructValue &refreshStructValue(AggregateStorageLocation &Loc, +Environment &Env) { + auto &NewVal = *cast(Env.createValue(Loc.getType())); + Env.setValue(Loc, NewVal); + return NewVal; +} + +StructValue &refreshStructValue(const Expr &Expr, Environment &Env) { + assert(Expr.getType()->isRecordType()); + + auto &NewVal = *cast(Env.createValue(Expr.getType())); + + if (Expr.isPRValue()) { +Env.setValueStrict(Expr, NewVal); + } else { +StorageLocation *Loc = Env.getStorageLocationStrict(Expr); +if (Loc == nullptr) { + Loc = &Env.createStorageLocation(Expr); +} +Env.setValue(*Loc, NewVal); + } + + return NewVal; +} + } // namespace dataflow } // namespace clang diff --git a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp index 11b346fbf64f3b..462ffb5eb389ce 100644 --- a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp @@ -370,13 +370,6 @@ TEST_F(NoreturnDestructorTest, ConditionalOperatorNestedBranchReturns) { // FIXME: Called functions at point `p` should contain only "foo". } -StructValue &createNewStructValue(AggregateStorageLocation &Loc, - Environment &Env) { - auto &Val = *cast(Env.createValue(Loc.getType())); - Env.setValue(Loc, Val); - return Val; -} - // Models an analysis that uses flow conditions. class SpecialBoolAnalysis fina
[clang] 6d76854 - [clang][dataflow] Add `DataflowEnvironment::createObject()`.
Author: Martin Braenne Date: 2023-07-17T07:26:10Z New Revision: 6d768548ecc0ca37026986f397392c1d0ace9736 URL: https://github.com/llvm/llvm-project/commit/6d768548ecc0ca37026986f397392c1d0ace9736 DIFF: https://github.com/llvm/llvm-project/commit/6d768548ecc0ca37026986f397392c1d0ace9736.diff LOG: [clang][dataflow] Add `DataflowEnvironment::createObject()`. This consolidates the code used in various places to initialize objects (usually for variables) into one central location. It will also help reduce the number of changes needed when we make the upcoming API changes to `AggregateStorageLocation` and `StructValue`. Depends On D155074 Reviewed By: ymandel, xazax.hun Differential Revision: https://reviews.llvm.org/D155075 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp clang/lib/Analysis/FlowSensitive/Transfer.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index 07af485e786c81..dc82ccea4a27d4 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -394,6 +394,32 @@ class Environment { /// `Type` must not be null. Value *createValue(QualType Type); + /// Creates an object (i.e. a storage location with an associated value) of + /// type `Ty`. If `InitExpr` is non-null and has a value associated with it, + /// initializes the object with this value. Otherwise, initializes the object + /// with a value created using `createValue()`. + StorageLocation &createObject(QualType Ty, const Expr *InitExpr = nullptr) { +return createObjectInternal(nullptr, Ty, InitExpr); + } + + /// Creates an object for the variable declaration `D`. If `D` has an + /// initializer and this initializer is associated with a value, initializes + /// the object with this value. Otherwise, initializes the object with a + /// value created using `createValue()`. Uses the storage location returned by + /// `DataflowAnalysisContext::getStableStorageLocation(D)`. + StorageLocation &createObject(const VarDecl &D) { +return createObjectInternal(&D, D.getType(), D.getInit()); + } + + /// Creates an object for the variable declaration `D`. If `InitExpr` is + /// non-null and has a value associated with it, initializes the object with + /// this value. Otherwise, initializes the object with a value created using + /// `createValue()`. Uses the storage location returned by + /// `DataflowAnalysisContext::getStableStorageLocation(D)`. + StorageLocation &createObject(const VarDecl &D, const Expr *InitExpr) { +return createObjectInternal(&D, D.getType(), InitExpr); + } + /// Assigns `Val` as the value of `Loc` in the environment. void setValue(const StorageLocation &Loc, Value &Val); @@ -592,6 +618,11 @@ class Environment { llvm::DenseSet &Visited, int Depth, int &CreatedValuesCount); + /// Shared implementation of `createObject()` overloads. + /// `D` and `InitExpr` may be null. + StorageLocation &createObjectInternal(const VarDecl *D, QualType Ty, +const Expr *InitExpr); + StorageLocation &skip(StorageLocation &Loc, SkipPast SP) const; const StorageLocation &skip(const StorageLocation &Loc, SkipPast SP) const; diff --git a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp index 531115efa64f94..bb1c2c7a1de10d 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp @@ -72,7 +72,7 @@ StorageLocation & DataflowAnalysisContext::getStableStorageLocation(const VarDecl &D) { if (auto *Loc = getStorageLocation(D)) return *Loc; - auto &Loc = createStorageLocation(D.getType()); + auto &Loc = createStorageLocation(D.getType().getNonReferenceType()); setStorageLocation(D, Loc); return Loc; } diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index a49c529c37a46b..fdd6b5959cd722 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -260,10 +260,8 @@ void Environment::initFieldsGlobalsAndFuncs(const FunctionDecl *FuncDecl) { for (const VarDecl *D : Vars) { if (getStorageLocation(*D) != nullptr) continue; -auto &Loc = createStorageLocation(D->getType().getNonReferenceType()); -setStorageLocation(*D, Loc); -if (auto *Val = createValue(D->get
[clang] 0f6cf55 - [clang][dataflow] Bugfix for `refreshStructValue()`.
Author: Martin Braenne Date: 2023-07-17T18:56:25Z New Revision: 0f6cf555674959d0b21769fc1c46e23584561f2a URL: https://github.com/llvm/llvm-project/commit/0f6cf555674959d0b21769fc1c46e23584561f2a DIFF: https://github.com/llvm/llvm-project/commit/0f6cf555674959d0b21769fc1c46e23584561f2a.diff LOG: [clang][dataflow] Bugfix for `refreshStructValue()`. In the case where the expression was not yet associated with a storage location, we created a new storage location but failed to associate it with the expression. The newly added test fails without the fix. Reviewed By: xazax.hun Differential Revision: https://reviews.llvm.org/D155465 Added: Modified: clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index 5d301b815d38e0..54632f5662b63d 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -1005,6 +1005,7 @@ StructValue &refreshStructValue(const Expr &Expr, Environment &Env) { StorageLocation *Loc = Env.getStorageLocationStrict(Expr); if (Loc == nullptr) { Loc = &Env.createStorageLocation(Expr); + Env.setStorageLocation(Expr, *Loc); } Env.setValue(*Loc, NewVal); } diff --git a/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp b/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp index e9531d1e7e8fd4..ba316f7d35e895 100644 --- a/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp @@ -25,6 +25,7 @@ namespace { using namespace clang; using namespace dataflow; using ::clang::dataflow::test::getFieldValue; +using ::testing::IsNull; using ::testing::NotNull; class EnvironmentTest : public ::testing::Test { @@ -252,4 +253,35 @@ TEST_F(EnvironmentTest, InitGlobalVarsConstructor) { EXPECT_THAT(Env.getValue(*Var), NotNull()); } +TEST_F(EnvironmentTest, RefreshStructValue) { + using namespace ast_matchers; + + std::string Code = R"cc( + struct S {}; + void target () { + S s; + s; + } + )cc"; + + auto Unit = + tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++11"}); + auto &Context = Unit->getASTContext(); + + ASSERT_EQ(Context.getDiagnostics().getClient()->getNumErrors(), 0U); + + auto Results = match(functionDecl(hasName("target")).bind("target"), Context); + const auto *Target = selectFirst("target", Results); + ASSERT_THAT(Target, NotNull()); + + Results = match(declRefExpr(to(varDecl(hasName("s".bind("s"), Context); + const auto *DRE = selectFirst("s", Results); + ASSERT_THAT(DRE, NotNull()); + + Environment Env(DAContext, *Target); + EXPECT_THAT(Env.getStorageLocationStrict(*DRE), IsNull()); + refreshStructValue(*DRE, Env); + EXPECT_THAT(Env.getStorageLocationStrict(*DRE), NotNull()); +} + } // namespace ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 4866a6e - [clang][dataflow] Produce pointer values for callees of member operator calls.
Author: Martin Braenne Date: 2023-08-24T07:12:14Z New Revision: 4866a6e1d3327a0499ef0e017a973a78d4e377bc URL: https://github.com/llvm/llvm-project/commit/4866a6e1d3327a0499ef0e017a973a78d4e377bc DIFF: https://github.com/llvm/llvm-project/commit/4866a6e1d3327a0499ef0e017a973a78d4e377bc.diff LOG: [clang][dataflow] Produce pointer values for callees of member operator calls. Calls to member operators are a special case in that their callees have pointer type. The callees of non-operator non-static member functions are not pointers. See the comments in the code for details. This issue came up in the Crubit nullability check; the fact that we weren't modeling the `PointerValue` caused non-convergence. Reviewed By: ymandel, xazax.hun Differential Revision: https://reviews.llvm.org/D158592 Added: Modified: clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp index 8617cf4c8ca4a2..200a981584bb76 100644 --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -175,12 +175,16 @@ class TransferVisitor : public ConstStmtVisitor { const ValueDecl *VD = S->getDecl(); assert(VD != nullptr); -// `DeclRefExpr`s to fields and non-static methods aren't glvalues, and -// there's also no sensible `Value` we can assign to them, so skip them. -if (isa(VD)) - return; -if (auto *Method = dyn_cast(VD); -Method && !Method->isStatic()) +// Some `DeclRefExpr`s aren't glvalues, so we can't associate them with a +// `StorageLocation`, and there's also no sensible `Value` that we can +// assign to them. Examples: +// - Non-static member variables +// - Non static member functions +// Note: Member operators are an exception to this, but apparently only +// if the `DeclRefExpr` is used within the callee of a +// `CXXOperatorCallExpr`. In other cases, for example when applying the +// address-of operator, the `DeclRefExpr` is a prvalue. +if (!S->isGLValue()) return; auto *DeclLoc = Env.getStorageLocation(*VD); diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index 4c31de3c8085bd..ef28f2f233b844 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -5588,6 +5588,59 @@ TEST(TransferTest, BuiltinFunctionModeled) { }); } +// Check that a callee of a member operator call is modeled as a `PointerValue`. +// Member operator calls are unusual in that their callee is a pointer that +// stems from a `FunctionToPointerDecay`. In calls to non-operator non-static +// member functions, the callee is a `MemberExpr` (which does not have pointer +// type). +// We want to make sure that we produce a pointer value for the callee in this +// specific scenario and that its storage location is durable (for convergence). +TEST(TransferTest, MemberOperatorCallModelsPointerForCallee) { + std::string Code = R"( +struct S { + bool operator!=(S s); +}; +void target() { + S s; + (void)(s != s); + (void)(s != s); + // [[p]] +} + )"; + runDataflow( + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) { +using ast_matchers::selectFirst; +using ast_matchers::match; +using ast_matchers::traverse; +using ast_matchers::cxxOperatorCallExpr; + +const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); + +auto Matches = match( +traverse(TK_AsIs, cxxOperatorCallExpr().bind("call")), ASTCtx); + +ASSERT_EQ(Matches.size(), 2); + +auto *Call1 = Matches[0].getNodeAs("call"); +auto *Call2 = Matches[1].getNodeAs("call"); + +ASSERT_THAT(Call1, NotNull()); +ASSERT_THAT(Call2, NotNull()); + +EXPECT_EQ(cast(Call1->getCallee())->getCastKind(), + CK_FunctionToPointerDecay); +EXPECT_EQ(cast(Call2->getCallee())->getCastKind(), + CK_FunctionToPointerDecay); + +auto *Ptr1 = cast(Env.getValue(*Call1->getCallee())); +auto *Ptr2 = cast(Env.getValue(*Call2->getCallee())); + +ASSERT_EQ(&Ptr1->getPointeeLoc(), &Ptr2->getPointeeLoc()); + }); +} + // Check that fields of anonymous records are modeled. TEST(TransferTest, AnonymousStruct) { std::string Code = R"( ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] aef05a1 - [clang][dataflow][NFC] Eliminate `getStorageLocation()` / `setStorageLocation()` in `DataflowAnalysisContext`.
Author: Martin Braenne Date: 2023-08-29T06:53:48Z New Revision: aef05a12329cf83c0a6fe46b464ab6ac08ee3439 URL: https://github.com/llvm/llvm-project/commit/aef05a12329cf83c0a6fe46b464ab6ac08ee3439 DIFF: https://github.com/llvm/llvm-project/commit/aef05a12329cf83c0a6fe46b464ab6ac08ee3439.diff LOG: [clang][dataflow][NFC] Eliminate `getStorageLocation()` / `setStorageLocation()` in `DataflowAnalysisContext`. Instead, inline them into the `getStableStorageLocation()` overloads, which is the only place they were called from (and should be called from). `getStorageLocation()` / `setStorageLocation()` were confusing because neither their name nor their documentation made reference to the fact that the storage location is stable. It didn't make sense to keep these as private member functions either. The code for the two `getStableStorageLocation()` overloads has become only marginally more complex by inlining these functions, and the `Expr` version is actually more efficient because we only call `ignoreCFGOmittedNodes()` once instead of twice. Reviewed By: ymandel, xazax.hun Differential Revision: https://reviews.llvm.org/D158981 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h index e5c325b876bd7a..685bbe486b54e1 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h @@ -103,39 +103,6 @@ class DataflowAnalysisContext { /// Returns a stable storage location for `E`. StorageLocation &getStableStorageLocation(const Expr &E); - /// Assigns `Loc` as the storage location of `D`. - /// - /// Requirements: - /// - /// `D` must not be assigned a storage location. - void setStorageLocation(const ValueDecl &D, StorageLocation &Loc) { -assert(!DeclToLoc.contains(&D)); -DeclToLoc[&D] = &Loc; - } - - /// Returns the storage location assigned to `D` or null if `D` has no - /// assigned storage location. - StorageLocation *getStorageLocation(const ValueDecl &D) const { -return DeclToLoc.lookup(&D); - } - - /// Assigns `Loc` as the storage location of `E`. - /// - /// Requirements: - /// - /// `E` must not be assigned a storage location. - void setStorageLocation(const Expr &E, StorageLocation &Loc) { -const Expr &CanonE = ignoreCFGOmittedNodes(E); -assert(!ExprToLoc.contains(&CanonE)); -ExprToLoc[&CanonE] = &Loc; - } - - /// Returns the storage location assigned to `E` or null if `E` has no - /// assigned storage location. - StorageLocation *getStorageLocation(const Expr &E) const { -return ExprToLoc.lookup(&ignoreCFGOmittedNodes(E)); - } - /// Returns a pointer value that represents a null pointer. Calls with /// `PointeeType` that are canonically equivalent will return the same result. /// A null `PointeeType` can be used for the pointee of `std::nullptr_t`. diff --git a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp index 0a6d7792208258..47a994f4bbdb6a 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp @@ -74,19 +74,21 @@ StorageLocation &DataflowAnalysisContext::createStorageLocation(QualType Type) { StorageLocation & DataflowAnalysisContext::getStableStorageLocation(const VarDecl &D) { - if (auto *Loc = getStorageLocation(D)) + if (auto *Loc = DeclToLoc.lookup(&D)) return *Loc; auto &Loc = createStorageLocation(D.getType().getNonReferenceType()); - setStorageLocation(D, Loc); + DeclToLoc[&D] = &Loc; return Loc; } StorageLocation & DataflowAnalysisContext::getStableStorageLocation(const Expr &E) { - if (auto *Loc = getStorageLocation(E)) + const Expr &CanonE = ignoreCFGOmittedNodes(E); + + if (auto *Loc = ExprToLoc.lookup(&CanonE)) return *Loc; - auto &Loc = createStorageLocation(E.getType()); - setStorageLocation(E, Loc); + auto &Loc = createStorageLocation(CanonE.getType()); + ExprToLoc[&CanonE] = &Loc; return Loc; } ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 330d5bc - [clang][dataflow] Don't associate prvalue expressions with storage locations.
Author: Martin Braenne Date: 2023-08-29T07:28:46Z New Revision: 330d5bcbf61043b5ca2bf5a65bd4488718c85e6e URL: https://github.com/llvm/llvm-project/commit/330d5bcbf61043b5ca2bf5a65bd4488718c85e6e DIFF: https://github.com/llvm/llvm-project/commit/330d5bcbf61043b5ca2bf5a65bd4488718c85e6e.diff LOG: [clang][dataflow] Don't associate prvalue expressions with storage locations. Instead, map prvalue expressions directly to values in a newly introduced map `Environment::ExprToVal`. This change introduces an additional member variable in `Environment` but is an overall win: - It is more conceptually correctly, since prvalues don't have storage locations. - It eliminates complexity from `Environment::setValue(const Expr &E, Value &Val)`. - It reduces the amount of data stored in `Environment`: A prvalue now has a single entry in `ExprToVal` instead of one in `ExprToLoc` and one in `LocToVal`. - Not allocating `StorageLocation`s for prvalues additionally reduces memory usage. This patch is the last step in the migration to strict handling of value categories (see https://discourse.llvm.org/t/70086 for details). The changes here are almost entirely internal to `Environment`. The only externally observable change is that when associating a `RecordValue` with the location returned by `Environment::getResultObjectLocation()` for a given expression, callers additionally need to associate the `RecordValue` with the expression themselves. Reviewed By: xazax.hun Differential Revision: https://reviews.llvm.org/D158977 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp clang/lib/Analysis/FlowSensitive/Transfer.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index f812c01d42040b..95514d940c3f6a 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -651,14 +651,17 @@ class Environment { // function being analyzed is only a function and not a method. RecordStorageLocation *ThisPointeeLoc = nullptr; - // Maps from program declarations and statements to storage locations that are + // Maps from declarations and glvalue expression to storage locations that are // assigned to them. Unlike the maps in `DataflowAnalysisContext`, these // include only storage locations that are in scope for a particular basic // block. llvm::DenseMap DeclToLoc; llvm::DenseMap ExprToLoc; + // Maps from prvalue expressions and storage locations to the values that + // are assigned to them. // We preserve insertion order so that join/widen process values in // deterministic sequence. This in turn produces deterministic SAT formulas. + llvm::MapVector ExprToVal; llvm::MapVector LocToVal; Atom FlowConditionToken; diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index f6c8f7d2d395ec..f15ea52d6b4699 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -171,6 +171,105 @@ static Value &widenDistinctValues(QualType Type, Value &Prev, return Current; } +// Returns whether the values in `Map1` and `Map2` compare equal for those +// keys that `Map1` and `Map2` have in common. +template +bool compareKeyToValueMaps(const llvm::MapVector &Map1, + const llvm::MapVector &Map2, + const Environment &Env1, const Environment &Env2, + Environment::ValueModel &Model) { + for (auto &Entry : Map1) { +Key K = Entry.first; +assert(K != nullptr); + +Value *Val = Entry.second; +assert(Val != nullptr); + +auto It = Map2.find(K); +if (It == Map2.end()) + continue; +assert(It->second != nullptr); + +if (!areEquivalentValues(*Val, *It->second) && +!compareDistinctValues(K->getType(), *Val, Env1, *It->second, Env2, + Model)) + return false; + } + + return true; +} + +// Perform a join on either `LocToVal` or `ExprToVal`. `Key` must be either +// `const StorageLocation *` or `const Expr *`. +template +llvm::MapVector +joinKeyToValueMap(const llvm::MapVector &Map1, + const llvm::MapVector &Map2, + const Environment &Env1, const Environment &Env2, + Environment &JoinedEnv, Environment::ValueModel &Model) { + llvm::MapVector MergedMap; + for (auto &Entry : Map1) { +Key K = Entry.first; +assert(K != nullptr); + +Value *Val = Entry.second; +asse
[clang] 6eb1b23 - [clang][dataflow][NFC] Remove obsolete references to `ReferenceValue` from comments.
Author: Martin Braenne Date: 2023-08-30T06:55:40Z New Revision: 6eb1b237f5eca0f9b16b66a1f4e8964554027e38 URL: https://github.com/llvm/llvm-project/commit/6eb1b237f5eca0f9b16b66a1f4e8964554027e38 DIFF: https://github.com/llvm/llvm-project/commit/6eb1b237f5eca0f9b16b66a1f4e8964554027e38.diff LOG: [clang][dataflow][NFC] Remove obsolete references to `ReferenceValue` from comments. `ReferenceValue` was removed in https://reviews.llvm.org/D155922. Reviewed By: xazax.hun Differential Revision: https://reviews.llvm.org/D159090 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h clang/include/clang/Analysis/FlowSensitive/Value.h clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index 95514d940c3f6a..f5e4057f957a96 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -254,17 +254,10 @@ class Environment { /// Requirements: /// /// `D` must not already have a storage location in the environment. - /// - /// If `D` has reference type, `Loc` must refer directly to the referenced - /// object (if any), not to a `ReferenceValue`, and it is not permitted to - /// later change `Loc` to refer to a `ReferenceValue.` void setStorageLocation(const ValueDecl &D, StorageLocation &Loc); /// Returns the storage location assigned to `D` in the environment, or null /// if `D` isn't assigned a storage location in the environment. - /// - /// Note that if `D` has reference type, the storage location that is returned - /// refers directly to the referenced object, not a `ReferenceValue`. StorageLocation *getStorageLocation(const ValueDecl &D) const; /// Assigns `Loc` as the storage location of the glvalue `E` in the @@ -280,9 +273,6 @@ class Environment { /// environment, or null if `E` isn't assigned a storage location in the /// environment. /// - /// If the storage location for `E` is associated with a - /// `ReferenceValue RefVal`, returns `RefVal.getReferentLoc()` instead. - /// /// Requirements: /// `E` must be a glvalue or a `BuiltinType::BuiltinFn` StorageLocation *getStorageLocation(const Expr &E) const; @@ -437,7 +427,6 @@ class Environment { /// Requirements: /// /// `E` must be a prvalue - /// `Val` must not be a `ReferenceValue` /// If `Val` is a `RecordValue`, its `RecordStorageLocation` must be the /// same as that of any `RecordValue` that has already been associated with /// `E`. This is to guarantee that the result object initialized by a prvalue diff --git a/clang/include/clang/Analysis/FlowSensitive/Value.h b/clang/include/clang/Analysis/FlowSensitive/Value.h index b2f71de593f995..da9fe6be9489c2 100644 --- a/clang/include/clang/Analysis/FlowSensitive/Value.h +++ b/clang/include/clang/Analysis/FlowSensitive/Value.h @@ -83,8 +83,8 @@ class Value { /// transitivity. It does *not* include comparison of `Properties`. /// /// Computes equivalence for these subclasses: -/// * ReferenceValue, PointerValue -- pointee locations are equal. Does not -/// compute deep equality of `Value` at said location. +/// * PointerValue -- pointee locations are equal. Does not compute deep +/// equality of `Value` at said location. /// * TopBoolValue -- both are `TopBoolValue`s. /// /// Otherwise, falls back to pointer equality. diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp index c0092694ef385d..fcd9b20027cde9 100644 --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -276,8 +276,7 @@ class TransferVisitor : public ConstStmtVisitor { case CK_LValueToRValue: { // When an L-value is used as an R-value, it may result in sharing, so we - // need to unpack any nested `Top`s. We also need to strip off the - // `ReferenceValue` associated with the lvalue. + // need to unpack any nested `Top`s. auto *SubExprVal = maybeUnpackLValueExpr(*SubExpr, Env); if (SubExprVal == nullptr) break; diff --git a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp index de0b5c7b239055..01162c89a36c8e 100644 --- a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp @@ -153,9 +153,9 @@ TEST(DataflowAnalysisTest, NonConvergingAnalysis) { // Regression test for joins of bool-typed lvalue expressions. The first loop // results i
[clang] 37458c6 - [clang][dataflow] Eliminate deprecated `DataflowAnalysis` constructor.
Author: Martin Braenne Date: 2023-09-04T07:00:11Z New Revision: 37458c66bfefaa4f4cb40043cb88413e5b826e3f URL: https://github.com/llvm/llvm-project/commit/37458c66bfefaa4f4cb40043cb88413e5b826e3f DIFF: https://github.com/llvm/llvm-project/commit/37458c66bfefaa4f4cb40043cb88413e5b826e3f.diff LOG: [clang][dataflow] Eliminate deprecated `DataflowAnalysis` constructor. Reviewed By: ymandel, xazax.hun Differential Revision: https://reviews.llvm.org/D159261 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h clang/include/clang/Analysis/FlowSensitive/NoopAnalysis.h clang/unittests/Analysis/FlowSensitive/ChromiumCheckModelTest.cpp clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h index db02e1b73c6aff7..abd34f40922121e 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h @@ -85,14 +85,6 @@ class DataflowAnalysis : public TypeErasedDataflowAnalysis { explicit DataflowAnalysis(ASTContext &Context) : Context(Context) {} - /// Deprecated. Use the `DataflowAnalysisOptions` constructor instead. - explicit DataflowAnalysis(ASTContext &Context, bool ApplyBuiltinTransfer) - : DataflowAnalysis( -Context, -{ApplyBuiltinTransfer - ? DataflowAnalysisContext::Options{} - : std::optional()}) {} - explicit DataflowAnalysis(ASTContext &Context, DataflowAnalysisOptions Options) : TypeErasedDataflowAnalysis(Options), Context(Context) {} diff --git a/clang/include/clang/Analysis/FlowSensitive/NoopAnalysis.h b/clang/include/clang/Analysis/FlowSensitive/NoopAnalysis.h index 016b6b3ba014540..393f68300cb80c1 100644 --- a/clang/include/clang/Analysis/FlowSensitive/NoopAnalysis.h +++ b/clang/include/clang/Analysis/FlowSensitive/NoopAnalysis.h @@ -27,15 +27,6 @@ class NoopAnalysis : public DataflowAnalysis { NoopAnalysis(ASTContext &Context) : DataflowAnalysis(Context) {} - /// Deprecated. Use the `DataflowAnalysisOptions` constructor instead. - NoopAnalysis(ASTContext &Context, bool ApplyBuiltinTransfer) - : DataflowAnalysis(Context, -ApplyBuiltinTransfer) {} - - /// `ApplyBuiltinTransfer` controls whether to run the built-in transfer - /// functions that model memory during the analysis. Their results are not - /// used by `NoopAnalysis`, but tests that need to inspect the environment - /// should enable them. NoopAnalysis(ASTContext &Context, DataflowAnalysisOptions Options) : DataflowAnalysis(Context, Options) {} diff --git a/clang/unittests/Analysis/FlowSensitive/ChromiumCheckModelTest.cpp b/clang/unittests/Analysis/FlowSensitive/ChromiumCheckModelTest.cpp index 0edf3ca6b359b27..1cb51a9cf37c5c4 100644 --- a/clang/unittests/Analysis/FlowSensitive/ChromiumCheckModelTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/ChromiumCheckModelTest.cpp @@ -113,8 +113,7 @@ class ModelAdaptorAnalysis : public DataflowAnalysis, NoopLattice> { public: explicit ModelAdaptorAnalysis(ASTContext &Context) - : DataflowAnalysis( -Context, /*ApplyBuiltinTransfer=*/true) {} + : DataflowAnalysis(Context) {} static NoopLattice initialElement() { return NoopLattice(); } diff --git a/clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp b/clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp index 937ab039f72f9ee..5de3dd8dccb68a9 100644 --- a/clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp @@ -86,7 +86,9 @@ void checkDataflow( Code, std::move(TargetFuncMatcher), [](ASTContext &Context, Environment &) { return NoopAnalysis( - Context, /*ApplyBuiltinTransfer=*/false); + Context, + // Don't apply builtin transfer function. + DataflowAnalysisOptions{std::nullopt}); }) .withASTBuildArgs({"-fsyntax-only", "-std=c++17"}), /*VerifyResults=*/std::move(Expectations)), diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index 8100db2aec40909..0a5cf62e5ea2332 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/cla
[clang] 266c12a - [clang][dataflow] When dumping `ExprToVal`, dump the `Value`, not just its location.
Author: Martin Braenne Date: 2023-09-04T07:38:33Z New Revision: 266c12a1bd603fa3ecbf26a6f93621f0f8488da1 URL: https://github.com/llvm/llvm-project/commit/266c12a1bd603fa3ecbf26a6f93621f0f8488da1 DIFF: https://github.com/llvm/llvm-project/commit/266c12a1bd603fa3ecbf26a6f93621f0f8488da1.diff LOG: [clang][dataflow] When dumping `ExprToVal`, dump the `Value`, not just its location. This makes `ExprToVal` dumping consistent with `LocToVal` dumping. Reviewed By: ymandel, xazax.hun Differential Revision: https://reviews.llvm.org/D159274 Added: Modified: clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index f15ea52d6b4699..b40fbbc991c8f8 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -918,7 +918,7 @@ void Environment::dump(raw_ostream &OS) const { OS << "ExprToVal:\n"; for (auto [E, V] : ExprToVal) -OS << " [" << E << ", " << V << "]\n"; +OS << " [" << E << ", " << V << ": " << *V << "]\n"; OS << "LocToVal:\n"; for (auto [L, V] : LocToVal) { ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] d948d91 - [clang][dataflow] Remove deprecated synonyms related to `RecordStorageLocation` and `RecordValue`
Author: Martin Braenne Date: 2023-09-04T08:18:43Z New Revision: d948d9121f104f06b47361528289030a28e1e044 URL: https://github.com/llvm/llvm-project/commit/d948d9121f104f06b47361528289030a28e1e044 DIFF: https://github.com/llvm/llvm-project/commit/d948d9121f104f06b47361528289030a28e1e044.diff LOG: [clang][dataflow] Remove deprecated synonyms related to `RecordStorageLocation` and `RecordValue` Reviewed By: ymandel, xazax.hun Differential Revision: https://reviews.llvm.org/D159264 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h clang/include/clang/Analysis/FlowSensitive/StorageLocation.h clang/include/clang/Analysis/FlowSensitive/Value.h Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index f5e4057f957a969..c128ee4ea85c928 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -690,15 +690,6 @@ RecordValue &refreshRecordValue(RecordStorageLocation &Loc, Environment &Env); /// See also documentation for the overload above. RecordValue &refreshRecordValue(const Expr &Expr, Environment &Env); -/// Deprecated synonym for `refreshRecordValue()`. -inline RecordValue &refreshStructValue(RecordStorageLocation &Loc, - Environment &Env) { - return refreshRecordValue(Loc, Env); -} -inline RecordValue &refreshStructValue(const Expr &Expr, Environment &Env) { - return refreshRecordValue(Expr, Env); -} - } // namespace dataflow } // namespace clang diff --git a/clang/include/clang/Analysis/FlowSensitive/StorageLocation.h b/clang/include/clang/Analysis/FlowSensitive/StorageLocation.h index 4a55adad74616ed..89d2bbfbb69f9fb 100644 --- a/clang/include/clang/Analysis/FlowSensitive/StorageLocation.h +++ b/clang/include/clang/Analysis/FlowSensitive/StorageLocation.h @@ -34,8 +34,6 @@ class StorageLocation { enum class Kind { Scalar, Record, -// Deprecated synonym for `Record` -Aggregate = Record, }; StorageLocation(Kind LocKind, QualType Type) : LocKind(LocKind), Type(Type) { @@ -155,9 +153,6 @@ class RecordStorageLocation final : public StorageLocation { FieldToLoc Children; }; -/// Deprecated synonym for `RecordStorageLocation`. -using AggregateStorageLocation = RecordStorageLocation; - } // namespace dataflow } // namespace clang diff --git a/clang/include/clang/Analysis/FlowSensitive/Value.h b/clang/include/clang/Analysis/FlowSensitive/Value.h index da9fe6be9489c20..6e911af7264ced9 100644 --- a/clang/include/clang/Analysis/FlowSensitive/Value.h +++ b/clang/include/clang/Analysis/FlowSensitive/Value.h @@ -36,8 +36,6 @@ class Value { Integer, Pointer, Record, -// Deprecated synonym for `Record` -Struct = Record, // TODO: Top values should not be need to be type-specific. TopBool, @@ -227,9 +225,6 @@ class RecordValue final : public Value { /// Returns the storage location that this `RecordValue` is associated with. RecordStorageLocation &getLoc() const { return Loc; } - /// Deprecated synonym for `getLoc()`. - RecordStorageLocation &getAggregateLoc() const { return Loc; } - /// Convenience function that returns the child storage location for `Field`. /// See also the documentation for `RecordStorageLocation::getChild()`. StorageLocation *getChild(const ValueDecl &Field) const { @@ -240,9 +235,6 @@ class RecordValue final : public Value { RecordStorageLocation &Loc; }; -/// Deprecated synonym for `RecordValue`. -using StructValue = RecordValue; - raw_ostream &operator<<(raw_ostream &OS, const Value &Val); } // namespace dataflow ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] bf46b0b - [clang][dataflow] Eliminate deprecated `ControlFlowContext::build()` overload.
Author: Martin Braenne Date: 2023-09-04T08:30:54Z New Revision: bf46b0b551011d958ae642f808894311513517ef URL: https://github.com/llvm/llvm-project/commit/bf46b0b551011d958ae642f808894311513517ef DIFF: https://github.com/llvm/llvm-project/commit/bf46b0b551011d958ae642f808894311513517ef.diff LOG: [clang][dataflow] Eliminate deprecated `ControlFlowContext::build()` overload. Reviewed By: ymandel, xazax.hun Differential Revision: https://reviews.llvm.org/D159262 Added: Modified: clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h b/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h index a45bb0635a2f363..768387a121b920a 100644 --- a/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h +++ b/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h @@ -40,12 +40,6 @@ class ControlFlowContext { static llvm::Expected build(const Decl &D, Stmt &S, ASTContext &C); - /// Builds a ControlFlowContext from an AST node. `D` is the function in which - /// `S` resides. `D` must not be null and `D->isTemplated()` must be false. - LLVM_DEPRECATED("Use the version that takes a const Decl & instead", "") - static llvm::Expected build(const Decl *D, Stmt &S, - ASTContext &C); - /// Returns the `Decl` containing the statement used to construct the CFG, if /// available. const Decl &getDecl() const { return ContainingDecl; } diff --git a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp index d5e0b443caf3015..7f9bc31bd41f2dd 100644 --- a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp +++ b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp @@ -109,15 +109,5 @@ ControlFlowContext::build(const Decl &D, Stmt &S, ASTContext &C) { std::move(BlockReachable)); } -llvm::Expected -ControlFlowContext::build(const Decl *D, Stmt &S, ASTContext &C) { - if (D == nullptr) -return llvm::createStringError( -std::make_error_code(std::errc::invalid_argument), -"Declaration must not be null"); - - return build(*D, S, C); -} - } // namespace dataflow } // namespace clang ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] b50c87d - [clang][dataflow] #llvm #flow-analysis Simplify formula at CNF construction time, and short-cut solving of known contradictory formulas.
Author: Burak Emir Date: 2023-09-05T06:23:04Z New Revision: b50c87d1e63f187105b5b73f7add37717ccce7f6 URL: https://github.com/llvm/llvm-project/commit/b50c87d1e63f187105b5b73f7add37717ccce7f6 DIFF: https://github.com/llvm/llvm-project/commit/b50c87d1e63f187105b5b73f7add37717ccce7f6.diff LOG: [clang][dataflow] #llvm #flow-analysis Simplify formula at CNF construction time, and short-cut solving of known contradictory formulas. In dataflow analysis, SAT solver: simplify formula during CNF construction and short-cut solving when the formula has been recognized as contradictory. Reviewed By: sammccall Differential Revision: https://reviews.llvm.org/D158407 Added: Modified: clang/lib/Analysis/FlowSensitive/WatchedLiteralsSolver.cpp clang/unittests/Analysis/FlowSensitive/SolverTest.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/WatchedLiteralsSolver.cpp b/clang/lib/Analysis/FlowSensitive/WatchedLiteralsSolver.cpp index 037886d09c4f7dd..05ae36ddbc898ec 100644 --- a/clang/lib/Analysis/FlowSensitive/WatchedLiteralsSolver.cpp +++ b/clang/lib/Analysis/FlowSensitive/WatchedLiteralsSolver.cpp @@ -12,8 +12,8 @@ //===--===// #include +#include #include -#include #include #include @@ -23,8 +23,10 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/STLExtras.h" + namespace clang { namespace dataflow { @@ -62,6 +64,10 @@ static constexpr Literal NullLit = 0; /// Returns the positive literal `V`. static constexpr Literal posLit(Variable V) { return 2 * V; } +static constexpr bool isPosLit(Literal L) { return 0 == (L & 1); } + +static constexpr bool isNegLit(Literal L) { return 1 == (L & 1); } + /// Returns the negative literal `!V`. static constexpr Literal negLit(Variable V) { return 2 * V + 1; } @@ -125,9 +131,14 @@ struct CNFFormula { /// formula. llvm::DenseMap Atomics; + /// Indicates that we already know the formula is unsatisfiable. + /// During construction, we catch simple cases of conflicting unit-clauses. + bool KnownContradictory; + explicit CNFFormula(Variable LargestVar, llvm::DenseMap Atomics) - : LargestVar(LargestVar), Atomics(std::move(Atomics)) { + : LargestVar(LargestVar), Atomics(std::move(Atomics)), +KnownContradictory(false) { Clauses.push_back(0); ClauseStarts.push_back(0); NextWatched.push_back(0); @@ -135,33 +146,24 @@ struct CNFFormula { WatchedHead.resize(NumLiterals + 1, 0); } - /// Adds the `L1 v L2 v L3` clause to the formula. If `L2` or `L3` are - /// `NullLit` they are respectively omitted from the clause. - /// + /// Adds the `L1 v ... v Ln` clause to the formula. /// Requirements: /// - /// `L1` must not be `NullLit`. + /// `Li` must not be `NullLit`. /// /// All literals in the input that are not `NullLit` must be distinct. - void addClause(Literal L1, Literal L2 = NullLit, Literal L3 = NullLit) { -// The literals are guaranteed to be distinct from properties of Formula -// and the construction in `buildCNF`. -assert(L1 != NullLit && L1 != L2 && L1 != L3 && - (L2 != L3 || L2 == NullLit)); + void addClause(ArrayRef lits) { +assert(!lits.empty()); +assert(llvm::all_of(lits, [](Literal L) { return L != NullLit; })); const ClauseID C = ClauseStarts.size(); const size_t S = Clauses.size(); ClauseStarts.push_back(S); - -Clauses.push_back(L1); -if (L2 != NullLit) - Clauses.push_back(L2); -if (L3 != NullLit) - Clauses.push_back(L3); +Clauses.insert(Clauses.end(), lits.begin(), lits.end()); // Designate the first literal as the "watched" literal of the clause. -NextWatched.push_back(WatchedHead[L1]); -WatchedHead[L1] = C; +NextWatched.push_back(WatchedHead[lits.front()]); +WatchedHead[lits.front()] = C; } /// Returns the number of literals in clause `C`. @@ -176,6 +178,84 @@ struct CNFFormula { } }; +/// Applies simplifications while building up a BooleanFormula. +/// We keep track of unit clauses, which tell us variables that must be +/// true/false in any model that satisfies the overall formula. +/// Such variables can be dropped from subsequently-added clauses, which +/// may in turn yield more unit clauses or even a contradiction. +/// The total added complexity of this preprocessing is O(N) where we +/// for every clause, we do a lookup for each unit clauses. +/// The lookup is O(1) on average. This method won't catch all +/// contradictory formulas, more passes can in principle catch +/// more cases but we leave all these and the general case to the +/// proper SAT solver. +struct CNFFormulaBuilder { + // Formula should outlive CNFFormulaBuilder. + explicit
[clang] f9026cf - [clang][dataflow] Fix Record initialization with InitListExpr and inheritances
Author: Kinuko Yasuda Date: 2023-09-07T07:37:50Z New Revision: f9026cfb7680e2c2a4c8c91dd33f710ea1d321a3 URL: https://github.com/llvm/llvm-project/commit/f9026cfb7680e2c2a4c8c91dd33f710ea1d321a3 DIFF: https://github.com/llvm/llvm-project/commit/f9026cfb7680e2c2a4c8c91dd33f710ea1d321a3.diff LOG: [clang][dataflow] Fix Record initialization with InitListExpr and inheritances Usually RecordValues for record objects (e.g. struct) are initialized with `Environment::createValue()` which internally calls `getObjectFields()` to collects all fields from the current and base classes, and then filter them with `ModeledValues` via `DACtx::getModeledFields()` so that the fields that are actually referenced are modeled. The consistent set of fields should be initialized when a record is initialized with an initializer list (InitListExpr), however the existing code's behavior was different. Before this patch: * When a struct is initialized with InitListExpr, its fields are initialized based on what is returned by `getFieldsForInitListExpr()`, which only collects the direct fields in the current class, but not from the base classes. Moreover, if the base classes have their own InitListExpr, values that are initialized by their InitListExpr's weren't merged into the child objects. After this patch: * When a struct is initialized with InitListExpr, it collects and merges the fields in the base classes that were initialized by their InitListExpr's. The code also asserts that the consistent set of fields are initialized with the ModeledFields. Reviewed By: mboehme Differential Revision: https://reviews.llvm.org/D159284 Added: Modified: clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp index fcd9b20027cde9..67d8be392ae605 100644 --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -27,12 +27,12 @@ #include "clang/Analysis/FlowSensitive/Value.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/OperatorKinds.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/Support/Casting.h" -#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Debug.h" +#include #include -#include -#include + +#define DEBUG_TYPE "dataflow" namespace clang { namespace dataflow { @@ -629,17 +629,66 @@ class TransferVisitor : public ConstStmtVisitor { return; } -std::vector Fields = -getFieldsForInitListExpr(Type->getAsRecordDecl()); llvm::DenseMap FieldLocs; -for (auto [Field, Init] : llvm::zip(Fields, S->inits())) { - assert(Field != nullptr); - assert(Init != nullptr); +// This only contains the direct fields for the given type. +std::vector FieldsForInit = +getFieldsForInitListExpr(Type->getAsRecordDecl()); - FieldLocs.insert({Field, &Env.createObject(Field->getType(), Init)}); +// `S->inits()` contains all the initializer epressions, including the +// ones for direct base classes. +auto Inits = S->inits(); +size_t InitIdx = 0; + +// Initialize base classes. +if (auto* R = S->getType()->getAsCXXRecordDecl()) { + assert(FieldsForInit.size() + R->getNumBases() == Inits.size()); + for ([[maybe_unused]] const CXXBaseSpecifier &Base : R->bases()) { +assert(InitIdx < Inits.size()); +auto Init = Inits[InitIdx++]; +assert(Base.getType().getCanonicalType() == + Init->getType().getCanonicalType()); +auto* BaseVal = cast_or_null(Env.getValue(*Init)); +if (!BaseVal) + BaseVal = cast(Env.createValue(Init->getType())); +// Take ownership of the fields of the `RecordValue` for the base class +// and incorporate them into the "flattened" set of fields for the +// derived class. +auto Children = BaseVal->getLoc().children(); +FieldLocs.insert(Children.begin(), Children.end()); + } } +assert(FieldsForInit.size() == Inits.size() - InitIdx); +for (auto Field : FieldsForInit) { + assert(InitIdx < Inits.size()); + auto Init = Inits[InitIdx++]; + assert( + // The types are same, or + Field->getType().getCanonicalType().getUnqualifiedType() == + Init->getType().getCanonicalType() || + // The field's type is T&, and initializer is T + (Field->getType()->isReferenceType() && + Field->getType().getCanonicalType()->getPointeeType() == + Init->getType().getCanonicalType())); + auto& Loc = Env.createObject(Field->getType(), Init); + FieldLocs.insert({Field, &Loc}); +} + +LLVM_DEBUG({ + // Check that we satisfy the invariant that a `RecordStorageLoation` + // contains
[clang-tools-extra] ddbcd98 - [clang-tidy] Correctly handle evaluation order of designated initializers.
Author: Martin Braenne Date: 2023-03-16T08:15:13Z New Revision: ddbcd985602dcb5fe78fcf2246cf53922db1f3c3 URL: https://github.com/llvm/llvm-project/commit/ddbcd985602dcb5fe78fcf2246cf53922db1f3c3 DIFF: https://github.com/llvm/llvm-project/commit/ddbcd985602dcb5fe78fcf2246cf53922db1f3c3.diff LOG: [clang-tidy] Correctly handle evaluation order of designated initializers. As designated initializers show up only in the syntactic form of the InitListExpr, we need to make sure we're searching both forms of the InitListExpr when determining successors in the evaluation order. This fixes a bug in bugprone-use-after-move where previously we erroneously concluded that two designated initializers were unsequenced. The newly added tests fail without the fix. Differential Revision: https://reviews.llvm.org/D145906 Added: Modified: clang-tools-extra/clang-tidy/utils/ExprSequence.cpp clang-tools-extra/docs/ReleaseNotes.rst clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp Removed: diff --git a/clang-tools-extra/clang-tidy/utils/ExprSequence.cpp b/clang-tools-extra/clang-tidy/utils/ExprSequence.cpp index beb4c44467a80..f9555be57e738 100644 --- a/clang-tools-extra/clang-tidy/utils/ExprSequence.cpp +++ b/clang-tools-extra/clang-tidy/utils/ExprSequence.cpp @@ -8,6 +8,7 @@ #include "ExprSequence.h" #include "clang/AST/ParentMapContext.h" +#include "llvm/ADT/SmallVector.h" #include namespace clang::tidy::utils { @@ -49,6 +50,7 @@ static SmallVector getParentStmts(const Stmt *S, } namespace { + bool isDescendantOrEqual(const Stmt *Descendant, const Stmt *Ancestor, ASTContext *Context) { if (Descendant == Ancestor) @@ -60,6 +62,17 @@ bool isDescendantOrEqual(const Stmt *Descendant, const Stmt *Ancestor, return false; } + +llvm::SmallVector +getAllInitListForms(const InitListExpr *InitList) { + llvm::SmallVector result = {InitList}; + if (const InitListExpr *AltForm = InitList->getSyntacticForm()) +result.push_back(AltForm); + if (const InitListExpr *AltForm = InitList->getSemanticForm()) +result.push_back(AltForm); + return result; +} + } // namespace ExprSequence::ExprSequence(const CFG *TheCFG, const Stmt *Root, @@ -111,9 +124,12 @@ const Stmt *ExprSequence::getSequenceSuccessor(const Stmt *S) const { } else if (const auto *InitList = dyn_cast(Parent)) { // Initializer list: Each initializer clause is sequenced after the // clauses that precede it. - for (unsigned I = 1; I < InitList->getNumInits(); ++I) { -if (InitList->getInit(I - 1) == S) - return InitList->getInit(I); + for (const InitListExpr *Form : getAllInitListForms(InitList)) { +for (unsigned I = 1; I < Form->getNumInits(); ++I) { + if (Form->getInit(I - 1) == S) { +return Form->getInit(I); + } +} } } else if (const auto *Compound = dyn_cast(Parent)) { // Compound statement: Each sub-statement is sequenced after the diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 2be8bfc51d675..b53516a742e2c 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -219,6 +219,10 @@ Changes in existing checks ` check when warning would be emitted in constructor for virtual base class initialization. +- Improved :doc:`bugprone-use-after-move + ` to understand that there is a + sequence point between designated initializers. + Removed checks ^^ diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp index 281f2083857ad..45cef8abfd1f6 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp @@ -1155,18 +1155,32 @@ void initializerListSequences() { int i; A a; }; -A a; -S1 s1{a.getInt(), std::move(a)}; +{ + A a; + S1 s1{a.getInt(), std::move(a)}; +} +{ + A a; + S1 s1{.i = a.getInt(), .a = std::move(a)}; +} } { struct S2 { A a; int i; }; -A a; -S2 s2{std::move(a), a.getInt()}; -// CHECK-NOTES: [[@LINE-1]]:25: warning: 'a' used after it was moved -// CHECK-NOTES: [[@LINE-2]]:11: note: move occurred here +{ + A a; + S2 s2{std::move(a), a.getInt()}; + // CHECK-NOTES: [[@LINE-1]]:27: warning: 'a' used after it was moved + // CHECK-NOTES: [[@LINE-2]]:13: note: move occurred here +} +{ + A a; + S2 s2{.a = std::move(a), .i = a.getInt()}; + // CHECK-NOTES: [[@LINE-1]]:37: warning: 'a' used after it was moved + // CHECK-NOTES: [[@LINE-2]]:13: note: move occurred here +} } } __
[clang] 5acd29e - [clang][dataflow] Fix crash when RHS of `&&` or `||` calls `noreturn` func.
Author: Martin Braenne Date: 2023-03-23T08:02:43Z New Revision: 5acd29eb4d9e411b3631c26babcd1d2655623f4a URL: https://github.com/llvm/llvm-project/commit/5acd29eb4d9e411b3631c26babcd1d2655623f4a DIFF: https://github.com/llvm/llvm-project/commit/5acd29eb4d9e411b3631c26babcd1d2655623f4a.diff LOG: [clang][dataflow] Fix crash when RHS of `&&` or `||` calls `noreturn` func. The crash happened because the transfer fucntion for `&&` and `||` unconditionally tried to retrieve the value of the RHS. However, if the RHS is unreachable, there is no environment for it, and trying to retrieve the operand's value causes an assertion failure. See also the comments in the code for further details. Reviewed By: xazax.hun, ymandel, sgatev, gribozavr2 Differential Revision: https://reviews.llvm.org/D146514 Added: Modified: clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h clang/include/clang/Analysis/FlowSensitive/Transfer.h clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp clang/unittests/Analysis/FlowSensitive/TestingSupport.h clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h b/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h index e641468f77d00..3495bdfc538cb 100644 --- a/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h +++ b/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h @@ -18,6 +18,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/Stmt.h" #include "clang/Analysis/CFG.h" +#include "llvm/ADT/BitVector.h" #include "llvm/ADT/DenseMap.h" #include "llvm/Support/Error.h" #include @@ -47,18 +48,26 @@ class ControlFlowContext { return StmtToBlock; } + /// Returns whether `B` is reachable from the entry block. + bool isBlockReachable(const CFGBlock &B) const { +return BlockReachable[B.getBlockID()]; + } + private: // FIXME: Once the deprecated `build` method is removed, mark `D` as "must not // be null" and add an assertion. ControlFlowContext(const Decl *D, std::unique_ptr Cfg, - llvm::DenseMap StmtToBlock) + llvm::DenseMap StmtToBlock, + llvm::BitVector BlockReachable) : ContainingDecl(D), Cfg(std::move(Cfg)), -StmtToBlock(std::move(StmtToBlock)) {} +StmtToBlock(std::move(StmtToBlock)), +BlockReachable(std::move(BlockReachable)) {} /// The `Decl` containing the statement used to construct the CFG. const Decl *ContainingDecl; std::unique_ptr Cfg; llvm::DenseMap StmtToBlock; + llvm::BitVector BlockReachable; }; } // namespace dataflow diff --git a/clang/include/clang/Analysis/FlowSensitive/Transfer.h b/clang/include/clang/Analysis/FlowSensitive/Transfer.h index 78a426ed94dd5..db3d780bf35e5 100644 --- a/clang/include/clang/Analysis/FlowSensitive/Transfer.h +++ b/clang/include/clang/Analysis/FlowSensitive/Transfer.h @@ -26,9 +26,9 @@ class StmtToEnvMap { public: virtual ~StmtToEnvMap() = default; - /// Returns the environment of the basic block that contains `S` or nullptr if - /// there isn't one. - /// FIXME: Ensure that the result can't be null and return a const reference. + /// Retrieves the environment of the basic block that contains `S`. + /// If `S` is reachable, returns a non-null pointer to the environment. + /// If `S` is not reachable, returns nullptr. virtual const Environment *getEnvironment(const Stmt &S) const = 0; }; diff --git a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp index 2492b5203724c..6699a0fc9d79e 100644 --- a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp +++ b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp @@ -16,6 +16,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/Stmt.h" #include "clang/Analysis/CFG.h" +#include "llvm/ADT/BitVector.h" #include "llvm/ADT/DenseMap.h" #include "llvm/Support/Error.h" #include @@ -44,6 +45,28 @@ buildStmtToBasicBlockMap(const CFG &Cfg) { return StmtToBlock; } +static llvm::BitVector findReachableBlocks(const CFG &Cfg) { + llvm::BitVector BlockReachable(Cfg.getNumBlockIDs(), false); + + llvm::SmallVector BlocksToVisit; + BlocksToVisit.push_back(&Cfg.getEntry()); + while (!BlocksToVisit.empty()) { +const CFGBlock *Block = BlocksToVisit.back(); +BlocksToVisit.pop_back(); + +if (BlockReachable[Block->getBlockID()]) + continue; + +BlockReachable[Block->getBlockID()] = true; + +for (const CFGBlock *Succ : Block->succs()) + if (Succ) +BlocksToVisit.push_back(Succ); + } + + return BlockReachable; +} + llvm::Expected ControlFlowContext::build(const Decl *D, St
[clang] 0608541 - [clang][dataflow][NFC] Eliminate StmtToEnvMap interface.
Author: Martin Braenne Date: 2023-03-28T08:05:57Z New Revision: 0608541aa4b5932c092251b846e7b87576e4f2d4 URL: https://github.com/llvm/llvm-project/commit/0608541aa4b5932c092251b846e7b87576e4f2d4 DIFF: https://github.com/llvm/llvm-project/commit/0608541aa4b5932c092251b846e7b87576e4f2d4.diff LOG: [clang][dataflow][NFC] Eliminate StmtToEnvMap interface. Instead, we turn StmtToEnvMap into a concrete class with the implementation that used to live in StmtToEnvMapImpl. The layering issue that originally required the indirection through the `StmtToEnvMap` interface no longer exists. Reviewed By: ymandel, xazax.hun, gribozavr2 Differential Revision: https://reviews.llvm.org/D146507 Added: Modified: clang/include/clang/Analysis/FlowSensitive/Transfer.h clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/Transfer.h b/clang/include/clang/Analysis/FlowSensitive/Transfer.h index db3d780bf35e5..58bb77c4905c5 100644 --- a/clang/include/clang/Analysis/FlowSensitive/Transfer.h +++ b/clang/include/clang/Analysis/FlowSensitive/Transfer.h @@ -17,6 +17,7 @@ #include "clang/AST/Stmt.h" #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h" #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" +#include "clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h" namespace clang { namespace dataflow { @@ -24,12 +25,18 @@ namespace dataflow { /// Maps statements to the environments of basic blocks that contain them. class StmtToEnvMap { public: - virtual ~StmtToEnvMap() = default; - - /// Retrieves the environment of the basic block that contains `S`. - /// If `S` is reachable, returns a non-null pointer to the environment. - /// If `S` is not reachable, returns nullptr. - virtual const Environment *getEnvironment(const Stmt &S) const = 0; + StmtToEnvMap(const ControlFlowContext &CFCtx, + llvm::ArrayRef> + BlockToState) + : CFCtx(CFCtx), BlockToState(BlockToState) {} + + /// Returns the environment of the basic block that contains `S`. + /// The result is guaranteed never to be null. + const Environment *getEnvironment(const Stmt &S) const; + +private: + const ControlFlowContext &CFCtx; + llvm::ArrayRef> BlockToState; }; /// Evaluates `S` and updates `Env` accordingly. diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp index a1ed37da54c28..be5c9992a6d9d 100644 --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -36,6 +36,16 @@ namespace clang { namespace dataflow { +const Environment *StmtToEnvMap::getEnvironment(const Stmt &S) const { + auto BlockIt = CFCtx.getStmtToBlock().find(&ignoreCFGOmittedNodes(S)); + assert(BlockIt != CFCtx.getStmtToBlock().end()); + if (!CFCtx.isBlockReachable(*BlockIt->getSecond())) +return nullptr; + const auto &State = BlockToState[BlockIt->getSecond()->getBlockID()]; + assert(State); + return &State->Env; +} + static BoolValue &evaluateBooleanEquality(const Expr &LHS, const Expr &RHS, Environment &Env) { if (auto *LHSValue = diff --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp index 08bcd5e65e379..8e821e5a75d4a 100644 --- a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp +++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp @@ -40,29 +40,6 @@ namespace clang { namespace dataflow { -class StmtToEnvMapImpl : public StmtToEnvMap { -public: - StmtToEnvMapImpl( - const ControlFlowContext &CFCtx, - llvm::ArrayRef> - BlockToState) - : CFCtx(CFCtx), BlockToState(BlockToState) {} - - const Environment *getEnvironment(const Stmt &S) const override { -auto BlockIt = CFCtx.getStmtToBlock().find(&ignoreCFGOmittedNodes(S)); -assert(BlockIt != CFCtx.getStmtToBlock().end()); -if (!CFCtx.isBlockReachable(*BlockIt->getSecond())) - return nullptr; -const auto &State = BlockToState[BlockIt->getSecond()->getBlockID()]; -assert(State); -return &State->Env; - } - -private: - const ControlFlowContext &CFCtx; - llvm::ArrayRef> BlockToState; -}; - /// Returns the index of `Block` in the successors of `Pred`. static int blockIndexInPredecessor(const CFGBlock &Pred, const CFGBlock &Block) { @@ -269,7 +246,7 @@ computeBlockInputState(const CFGBlock &Block, AnalysisContext &AC) { TypeErasedDataflowAnalysisState PredState = *MaybePredState; if (Analysis.builtinOptions()) { if (const Stmt *PredTerminatorStmt = Pred->getTerminatorStmt()) { -const StmtToEnvMapImpl StmtToEnv(AC.CFCtx, AC.BlockSta
[clang] 1bc2d43 - [clang][dataflow][NFC] Put TransferVisitor in an unnamed namespace.
Author: Martin Braenne Date: 2023-03-28T10:03:39Z New Revision: 1bc2d43e5c8fd0ec2e1a7e364fb42272ed7fb158 URL: https://github.com/llvm/llvm-project/commit/1bc2d43e5c8fd0ec2e1a7e364fb42272ed7fb158 DIFF: https://github.com/llvm/llvm-project/commit/1bc2d43e5c8fd0ec2e1a7e364fb42272ed7fb158.diff LOG: [clang][dataflow][NFC] Put TransferVisitor in an unnamed namespace. This avoids the risk of ODR violations. Reviewed By: gribozavr2 Differential Revision: https://reviews.llvm.org/D147032 Added: Modified: clang/lib/Analysis/FlowSensitive/Transfer.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp index be5c9992a6d9d..d255d27e52c45 100644 --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -139,6 +139,8 @@ static Value *maybeUnpackLValueExpr(const Expr &E, Environment &Env) { return &UnpackedVal; } +namespace { + class TransferVisitor : public ConstStmtVisitor { public: TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env) @@ -884,6 +886,8 @@ class TransferVisitor : public ConstStmtVisitor { Environment &Env; }; +} // namespace + void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env) { TransferVisitor(StmtToEnv, Env).Visit(&S); } ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 762cb1d - [clang][dataflow] Create `Value`s for integer literals.
Author: Martin Braenne Date: 2023-06-19T08:37:41Z New Revision: 762cb1d377362daff234ac5172c2c1db4918f6d3 URL: https://github.com/llvm/llvm-project/commit/762cb1d377362daff234ac5172c2c1db4918f6d3 DIFF: https://github.com/llvm/llvm-project/commit/762cb1d377362daff234ac5172c2c1db4918f6d3.diff LOG: [clang][dataflow] Create `Value`s for integer literals. This patch includes a test that fails without the fix. I discovered that we weren't creating `Value`s for integer literals when, in a different patch, I tried to overwrite the value of a struct field with a literal for the purposes of a test and was surprised to find that the struct compared the same before and after the assignment. This functionality therefore seems useful at least for tests, but is probably also useful for actual analysis of code. Reviewed By: ymandel, xazax.hun, gribozavr2 Differential Revision: https://reviews.llvm.org/D152813 Added: Modified: clang/include/clang/Analysis/FlowSensitive/Arena.h clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h clang/lib/Analysis/FlowSensitive/Arena.cpp clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/Arena.h b/clang/include/clang/Analysis/FlowSensitive/Arena.h index d8a123c52eb83..83b4ddeec0256 100644 --- a/clang/include/clang/Analysis/FlowSensitive/Arena.h +++ b/clang/include/clang/Analysis/FlowSensitive/Arena.h @@ -84,6 +84,12 @@ class Arena { /// will be a value that represents the true boolean literal. BoolValue &makeEquals(BoolValue &LHS, BoolValue &RHS); + /// Returns a symbolic integer value that models an integer literal equal to + /// `Value`. These literals are the same every time. + /// Integer literals are not typed; the type is determined by the `Expr` that + /// an integer literal is associated with. + IntegerValue &makeIntLiteral(llvm::APInt Value); + /// Returns a symbolic boolean value that models a boolean literal equal to /// `Value`. These literals are the same every time. AtomicBoolValue &makeLiteral(bool Value) const { @@ -103,8 +109,9 @@ class Arena { std::vector> Locs; std::vector> Vals; - // Indices that are used to avoid recreating the same composite boolean - // values. + // Indices that are used to avoid recreating the same integer literals and + // composite boolean values. + llvm::DenseMap IntegerLiterals; llvm::DenseMap, ConjunctionValue *> ConjunctionVals; llvm::DenseMap, DisjunctionValue *> diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index a31f5ec116425..059cb841e89c7 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -448,6 +448,12 @@ class Environment { return DACtx->arena().create(std::forward(args)...); } + /// Returns a symbolic integer value that models an integer literal equal to + /// `Value` + IntegerValue &getIntLiteralValue(llvm::APInt Value) const { +return DACtx->arena().makeIntLiteral(Value); + } + /// Returns a symbolic boolean value that models a boolean literal equal to /// `Value` AtomicBoolValue &getBoolLiteralValue(bool Value) const { diff --git a/clang/lib/Analysis/FlowSensitive/Arena.cpp b/clang/lib/Analysis/FlowSensitive/Arena.cpp index a0182af85a228..cff6c45e18542 100644 --- a/clang/lib/Analysis/FlowSensitive/Arena.cpp +++ b/clang/lib/Analysis/FlowSensitive/Arena.cpp @@ -68,4 +68,12 @@ BoolValue &Arena::makeEquals(BoolValue &LHS, BoolValue &RHS) { return *Res.first->second; } +IntegerValue &Arena::makeIntLiteral(llvm::APInt Value) { + auto [It, Inserted] = IntegerLiterals.try_emplace(Value, nullptr); + + if (Inserted) +It->second = &create(); + return *It->second; +} + } // namespace clang::dataflow diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp index e0cb872cfa372..e7f596ace6aaa 100644 --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -48,9 +48,15 @@ const Environment *StmtToEnvMap::getEnvironment(const Stmt &S) const { static BoolValue &evaluateBooleanEquality(const Expr &LHS, const Expr &RHS, Environment &Env) { - if (auto *LHSValue = dyn_cast_or_null(Env.getValueStrict(LHS))) -if (auto *RHSValue = dyn_cast_or_null(Env.getValueStrict(RHS))) - return Env.makeIff(*LHSValue, *RHSValue); + Value *LHSValue = Env.getValueStrict(LHS); + Value *RHSValue = Env.getValueStrict(RHS); + + if (LHSValue == RHSValue) +return Env.getBoolLiteralValue(true); + + if (auto *LHSBool = dyn_cast_or_null(LHSValue)) +if (auto *RHSBool = d
[clang] efbb4aa - [clang][dataflow] Dump useful debugging information when we crash.
Author: Martin Braenne Date: 2023-06-23T06:49:28Z New Revision: efbb4aaacedf0ded734d0b40c42d4419d03a59ff URL: https://github.com/llvm/llvm-project/commit/efbb4aaacedf0ded734d0b40c42d4419d03a59ff DIFF: https://github.com/llvm/llvm-project/commit/efbb4aaacedf0ded734d0b40c42d4419d03a59ff.diff LOG: [clang][dataflow] Dump useful debugging information when we crash. - The AST of the function we're currently analyzing - The CFG - The CFG element we're currently processing Reviewed By: ymandel Differential Revision: https://reviews.llvm.org/D153549 Added: Modified: clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp index 38853c4d75429..de22d63812574 100644 --- a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp +++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp @@ -18,6 +18,7 @@ #include #include +#include "clang/AST/ASTDumper.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/OperationKinds.h" #include "clang/AST/StmtVisitor.h" @@ -179,6 +180,47 @@ struct AnalysisContext { llvm::ArrayRef> BlockStates; }; +class PrettyStackTraceAnalysis : public llvm::PrettyStackTraceEntry { +public: + PrettyStackTraceAnalysis(const ControlFlowContext &CFCtx, const char *Message) + : CFCtx(CFCtx), Message(Message) {} + + void print(raw_ostream &OS) const override { +OS << Message << "\n"; +OS << "Decl:\n"; +CFCtx.getDecl()->dump(OS); +OS << "CFG:\n"; +CFCtx.getCFG().print(OS, LangOptions(), false); + } + +private: + const ControlFlowContext &CFCtx; + const char *Message; +}; + +class PrettyStackTraceCFGElement : public llvm::PrettyStackTraceEntry { +public: + PrettyStackTraceCFGElement(const CFGElement &Element, int BlockIdx, + int ElementIdx, const char *Message) + : Element(Element), BlockIdx(BlockIdx), ElementIdx(ElementIdx), +Message(Message) {} + + void print(raw_ostream &OS) const override { +OS << Message << ": Element [B" << BlockIdx << "." << ElementIdx << "]\n"; +if (auto Stmt = Element.getAs()) { + OS << "Stmt:\n"; + ASTDumper Dumper(OS, false); + Dumper.Visit(Stmt->getStmt()); +} + } + +private: + const CFGElement ∈ + int BlockIdx; + int ElementIdx; + const char *Message; +}; + } // namespace /// Computes the input state for a given basic block by joining the output @@ -357,7 +399,11 @@ transferCFGBlock(const CFGBlock &Block, AnalysisContext &AC, AC.Log.enterBlock(Block); auto State = computeBlockInputState(Block, AC); AC.Log.recordState(State); + int ElementIdx = 1; for (const auto &Element : Block) { +PrettyStackTraceCFGElement CrashInfo(Element, Block.getBlockID(), + ElementIdx++, "transferCFGBlock"); + AC.Log.enterElement(Element); // Built-in analysis if (AC.Analysis.builtinOptions()) { @@ -395,6 +441,8 @@ runTypeErasedDataflowAnalysis( std::function PostVisitCFG) { + PrettyStackTraceAnalysis CrashInfo(CFCtx, "runTypeErasedDataflowAnalysis"); + PostOrderCFGView POV(&CFCtx.getCFG()); ForwardDataflowWorklist Worklist(CFCtx.getCFG(), &POV); ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] f2123af - [clang][dataflow] Perform deep copies in copy and move operations.
Author: Martin Braenne Date: 2023-06-26T13:52:56Z New Revision: f2123af1e7d7555af92b1bcff91bd5d0679a9b55 URL: https://github.com/llvm/llvm-project/commit/f2123af1e7d7555af92b1bcff91bd5d0679a9b55 DIFF: https://github.com/llvm/llvm-project/commit/f2123af1e7d7555af92b1bcff91bd5d0679a9b55.diff LOG: [clang][dataflow] Perform deep copies in copy and move operations. This serves two purposes: - Because, today, we only copy the `StructValue`, modifying the destination of the copy also modifies the source. This is demonstrated by the new checks added to `CopyConstructor` and `MoveConstructor`, which fail without the deep copy. - It lays the groundwork for eliminating the redundancy between `AggregateStorageLocation` and `StructValue`, which will happen as part of the ongoing migration to strict handling of value categories (seeo https://discourse.llvm.org/t/70086 for details). This will involve turning `StructValue` into essentially just a wrapper for `AggregateStorageLocation`; under this scheme, the current "shallow" copy (copying a `StructValue` from one `AggregateStorageLocation` to another) will no longer be possible. Because we now perform deep copies, tests need to perform a deep equality comparison instead of just comparing for equal identity of the `StructValue`s. The new function `recordsEqual()` provides such a deep equality comparison. Reviewed By: xazax.hun Differential Revision: https://reviews.llvm.org/D153006 Added: clang/include/clang/Analysis/FlowSensitive/RecordOps.h clang/lib/Analysis/FlowSensitive/RecordOps.cpp clang/unittests/Analysis/FlowSensitive/RecordOpsTest.cpp Modified: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h clang/include/clang/Analysis/FlowSensitive/StorageLocation.h clang/include/clang/Analysis/FlowSensitive/Value.h clang/lib/Analysis/FlowSensitive/CMakeLists.txt clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/unittests/Analysis/FlowSensitive/CMakeLists.txt clang/unittests/Analysis/FlowSensitive/TestingSupport.h clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index 1184fa60bd234..15e63c3d91a32 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -397,6 +397,9 @@ class Environment { /// Assigns `Val` as the value of `Loc` in the environment. void setValue(const StorageLocation &Loc, Value &Val); + /// Clears any association between `Loc` and a value in the environment. + void clearValue(const StorageLocation &Loc); + /// Assigns `Val` as the value of the prvalue `E` in the environment. /// /// If `E` is not yet associated with a storage location, associates it with diff --git a/clang/include/clang/Analysis/FlowSensitive/RecordOps.h b/clang/include/clang/Analysis/FlowSensitive/RecordOps.h new file mode 100644 index 0..f5a0a5a501c11 --- /dev/null +++ b/clang/include/clang/Analysis/FlowSensitive/RecordOps.h @@ -0,0 +1,71 @@ +//===-- RecordOps.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 +// +//===--===// +// +// Operations on records (structs, classes, and unions). +// +//===--===// + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_RECORDOPS_H +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_RECORDOPS_H + +#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" +#include "clang/Analysis/FlowSensitive/StorageLocation.h" + +namespace clang { +namespace dataflow { + +/// Copies a record (struct, class, or union) from `Src` to `Dst`. +/// +/// This performs a deep copy, i.e. it copies every field and recurses on +/// fields of record type. It also copies properties from the `StructValue` +/// associated with `Dst` to the `StructValue` associated with `Src` (if these +/// `StructValue`s exist). +/// +/// If there is a `StructValue` associated with `Dst` in the environment, this +/// function creates a new `StructValue` and associates it with `Dst`; clients +/// need to be aware of this and must not assume that the `StructValue` +/// associated with `Dst` remains the same after the call. +/// +/// We create a new `StructValue` rather than modifying properties on the old +/// `StructValue` because the old `StructValue` may be shared with other +/// `Environment`s, and we don't want changes to proper
[clang] 9a4097e - [clang][dataflow] Use namespace qualifiers when defining functions.
Author: Martin Braenne Date: 2023-06-27T08:56:21Z New Revision: 9a4097e9cd891e1445ba07ac6a21fe117fce URL: https://github.com/llvm/llvm-project/commit/9a4097e9cd891e1445ba07ac6a21fe117fce DIFF: https://github.com/llvm/llvm-project/commit/9a4097e9cd891e1445ba07ac6a21fe117fce.diff LOG: [clang][dataflow] Use namespace qualifiers when defining functions. See https://llvm.org/docs/CodingStandards.html#use-namespace-qualifiers-to-implement-previously-declared-functions Thank you to MaskRay for pointing this out on https://reviews.llvm.org/D153006 Reviewed By: xazax.hun Differential Revision: https://reviews.llvm.org/D153833 Added: Modified: clang/lib/Analysis/FlowSensitive/RecordOps.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/RecordOps.cpp b/clang/lib/Analysis/FlowSensitive/RecordOps.cpp index d7145b0e2b312..eac9e3d4f93f2 100644 --- a/clang/lib/Analysis/FlowSensitive/RecordOps.cpp +++ b/clang/lib/Analysis/FlowSensitive/RecordOps.cpp @@ -14,11 +14,9 @@ #define DEBUG_TYPE "dataflow" -namespace clang { -namespace dataflow { - -void copyRecord(AggregateStorageLocation &Src, AggregateStorageLocation &Dst, -Environment &Env) { +void clang::dataflow::copyRecord(AggregateStorageLocation &Src, + AggregateStorageLocation &Dst, + Environment &Env) { LLVM_DEBUG({ if (Dst.getType().getCanonicalType().getUnqualifiedType() != Src.getType().getCanonicalType().getUnqualifiedType()) { @@ -62,9 +60,10 @@ void copyRecord(AggregateStorageLocation &Src, AggregateStorageLocation &Dst, } } -bool recordsEqual(const AggregateStorageLocation &Loc1, const Environment &Env1, - const AggregateStorageLocation &Loc2, - const Environment &Env2) { +bool clang::dataflow::recordsEqual(const AggregateStorageLocation &Loc1, + const Environment &Env1, + const AggregateStorageLocation &Loc2, + const Environment &Env2) { LLVM_DEBUG({ if (Loc2.getType().getCanonicalType().getUnqualifiedType() != Loc1.getType().getCanonicalType().getUnqualifiedType()) { @@ -124,6 +123,3 @@ bool recordsEqual(const AggregateStorageLocation &Loc1, const Environment &Env1, return true; } - -} // namespace dataflow -} // namespace clang ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] d04b198 - [clang][dataflow] Add a test that we can access fields of anonymous records.
Author: Martin Braenne Date: 2023-06-28T09:12:03Z New Revision: d04b198973c9bda2376209b460943ac393190752 URL: https://github.com/llvm/llvm-project/commit/d04b198973c9bda2376209b460943ac393190752 DIFF: https://github.com/llvm/llvm-project/commit/d04b198973c9bda2376209b460943ac393190752.diff LOG: [clang][dataflow] Add a test that we can access fields of anonymous records. Reviewed By: sammccall, ymandel, gribozavr2, xazax.hun Differential Revision: https://reviews.llvm.org/D153409 Added: Modified: clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp clang/unittests/Analysis/FlowSensitive/TestingSupport.h clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp b/clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp index 0d441b71e69c6..a88b8d88c74c0 100644 --- a/clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp @@ -154,9 +154,19 @@ test::buildStatementToAnnotationMapping(const FunctionDecl *Func, } const ValueDecl *test::findValueDecl(ASTContext &ASTCtx, llvm::StringRef Name) { - auto TargetNodes = match(valueDecl(hasName(Name)).bind("v"), ASTCtx); + auto TargetNodes = match( + valueDecl(unless(indirectFieldDecl()), hasName(Name)).bind("v"), ASTCtx); assert(TargetNodes.size() == 1 && "Name must be unique"); auto *const Result = selectFirst("v", TargetNodes); assert(Result != nullptr); return Result; } + +const IndirectFieldDecl *test::findIndirectFieldDecl(ASTContext &ASTCtx, + llvm::StringRef Name) { + auto TargetNodes = match(indirectFieldDecl(hasName(Name)).bind("i"), ASTCtx); + assert(TargetNodes.size() == 1 && "Name must be unique"); + const auto *Result = selectFirst("i", TargetNodes); + assert(Result != nullptr); + return Result; +} diff --git a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h index e22600d7b2e44..856737d034855 100644 --- a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h +++ b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h @@ -428,6 +428,14 @@ runDataflowReturnError(llvm::StringRef Code, VerifyResultsT VerifyResults, /// `Name` must be unique in `ASTCtx`. const ValueDecl *findValueDecl(ASTContext &ASTCtx, llvm::StringRef Name); +/// Returns the `IndirectFieldDecl` for the given identifier. +/// +/// Requirements: +/// +/// `Name` must be unique in `ASTCtx`. +const IndirectFieldDecl *findIndirectFieldDecl(ASTContext &ASTCtx, + llvm::StringRef Name); + /// Returns the storage location (of type `LocT`) for the given identifier. /// `LocT` must be a subclass of `StorageLocation` and must be of the /// appropriate type. diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index 5e7abcc6ce750..51550adeea894 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -5434,4 +5434,38 @@ TEST(TransferTest, BuiltinFunctionModeled) { }); } +// Check that fields of anonymous records are modeled. +TEST(TransferTest, AnonymousStruct) { + std::string Code = R"( +struct S { + struct { +bool b; + }; +}; +void target() { + S s; + s.b = true; + // [[p]] +} + )"; + runDataflow( + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) { +const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); +const ValueDecl *SDecl = findValueDecl(ASTCtx, "s"); +const ValueDecl *BDecl = findValueDecl(ASTCtx, "b"); +const IndirectFieldDecl *IndirectField = +findIndirectFieldDecl(ASTCtx, "b"); + +auto *S = +cast(Env.getStorageLocation(*SDecl)); +auto &AnonStruct = cast( +S->getChild(*cast(IndirectField->chain().front(; + +auto *B = cast(Env.getValue(AnonStruct.getChild(*BDecl))); +ASSERT_TRUE(Env.flowConditionImplies(*B)); + }); +} + } // namespace ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 834a84d - [clang][dataflow] Output debug info if `getChild()` doesn't find field.
Author: Martin Braenne Date: 2023-06-28T09:12:08Z New Revision: 834a84d091ab7d196e966d8f08101136eb1c1e06 URL: https://github.com/llvm/llvm-project/commit/834a84d091ab7d196e966d8f08101136eb1c1e06 DIFF: https://github.com/llvm/llvm-project/commit/834a84d091ab7d196e966d8f08101136eb1c1e06.diff LOG: [clang][dataflow] Output debug info if `getChild()` doesn't find field. Depends On D153409 Reviewed By: xazax.hun Differential Revision: https://reviews.llvm.org/D153851 Added: Modified: clang/include/clang/Analysis/FlowSensitive/StorageLocation.h Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/StorageLocation.h b/clang/include/clang/Analysis/FlowSensitive/StorageLocation.h index 58ebb9bf52586..453f1e13362b7 100644 --- a/clang/include/clang/Analysis/FlowSensitive/StorageLocation.h +++ b/clang/include/clang/Analysis/FlowSensitive/StorageLocation.h @@ -17,6 +17,9 @@ #include "clang/AST/Decl.h" #include "clang/AST/Type.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/Support/Debug.h" + +#define DEBUG_TYPE "dataflow" namespace clang { namespace dataflow { @@ -85,6 +88,17 @@ class AggregateStorageLocation final : public StorageLocation { /// Returns the child storage location for `D`. StorageLocation &getChild(const ValueDecl &D) const { auto It = Children.find(&D); +LLVM_DEBUG({ + if (It == Children.end()) { +llvm::dbgs() << "Couldn't find child " << D.getNameAsString() + << " on StorageLocation " << this << " of type " + << getType() << "\n"; +llvm::dbgs() << "Existing children:\n"; +for ([[maybe_unused]] auto [Field, Loc] : Children) { + llvm::dbgs() << Field->getNameAsString() << "\n"; +} + } +}); assert(It != Children.end()); return *It->second; } @@ -100,4 +114,6 @@ class AggregateStorageLocation final : public StorageLocation { } // namespace dataflow } // namespace clang +#undef DEBUG_TYPE + #endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_STORAGELOCATION_H ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] abc8367 - [clang][dataflow] Don't crash if copy constructor arg doesn't have a storage location.
Author: Martin Braenne Date: 2023-06-28T11:15:52Z New Revision: abc8367413ff377b79e9743ca85252f209f81d65 URL: https://github.com/llvm/llvm-project/commit/abc8367413ff377b79e9743ca85252f209f81d65 DIFF: https://github.com/llvm/llvm-project/commit/abc8367413ff377b79e9743ca85252f209f81d65.diff LOG: [clang][dataflow] Don't crash if copy constructor arg doesn't have a storage location. I accidentally used `cast` instead of `cast_or_null`. Reviewed By: sammccall, xazax.hun Differential Revision: https://reviews.llvm.org/D153956 Added: Modified: clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp index c09b6b9a99ac3..54b8b3a108dc0 100644 --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -598,7 +598,7 @@ class TransferVisitor : public ConstStmtVisitor { const Expr *Arg = S->getArg(0); assert(Arg != nullptr); - auto *ArgLoc = cast( + auto *ArgLoc = cast_or_null( Env.getStorageLocation(*Arg, SkipPast::Reference)); if (ArgLoc == nullptr) return; diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index 51550adeea894..f41c3f2fdd2f7 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -2237,6 +2237,21 @@ TEST(TransferTest, CopyConstructorWithParens) { }); } +TEST(TransferTest, CopyConstructorArgIsRefReturnedByFunction) { + // This is a crash repro. + std::string Code = R"( +struct S {}; +const S &returnsSRef(); +void target() { + S s(returnsSRef()); +} + )"; + runDataflow( + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) {}); +} + TEST(TransferTest, MoveConstructor) { std::string Code = R"( namespace std { ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 74d8455 - [clang][dataflow] Make `getThisPointeeStorageLocation()` return an `AggregateStorageLocation`.
Author: Martin Braenne Date: 2023-06-29T04:07:08Z New Revision: 74d8455ba6a19d9eeaa561fd0eccc8cbf5351a47 URL: https://github.com/llvm/llvm-project/commit/74d8455ba6a19d9eeaa561fd0eccc8cbf5351a47 DIFF: https://github.com/llvm/llvm-project/commit/74d8455ba6a19d9eeaa561fd0eccc8cbf5351a47.diff LOG: [clang][dataflow] Make `getThisPointeeStorageLocation()` return an `AggregateStorageLocation`. This avoids the need for casts at callsites. Depends On D153852 Reviewed By: sammccall, xazax.hun, gribozavr2 Differential Revision: https://reviews.llvm.org/D153854 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index 8da359880e3ce3..faeb5eb69cd838 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -330,7 +330,7 @@ class Environment { /// Returns the storage location assigned to the `this` pointee in the /// environment or null if the `this` pointee has no assigned storage location /// in the environment. - StorageLocation *getThisPointeeStorageLocation() const; + AggregateStorageLocation *getThisPointeeStorageLocation() const; /// Returns the return value of the current function. This can be null if: /// - The function has a void return type @@ -600,7 +600,7 @@ class Environment { StorageLocation *ReturnLoc = nullptr; // The storage location of the `this` pointee. Should only be null if the // function being analyzed is only a function and not a method. - StorageLocation *ThisPointeeLoc = nullptr; + AggregateStorageLocation *ThisPointeeLoc = nullptr; // Maps from program declarations and statements to storage locations that are // assigned to them. Unlike the maps in `DataflowAnalysisContext`, these diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index f4867c4becea03..689f8abb51c8e0 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -309,7 +309,8 @@ Environment::Environment(DataflowAnalysisContext &DACtx, // FIXME: Initialize the ThisPointeeLoc of lambdas too. if (MethodDecl && !MethodDecl->isStatic()) { QualType ThisPointeeType = MethodDecl->getThisObjectType(); - ThisPointeeLoc = &createStorageLocation(ThisPointeeType); + ThisPointeeLoc = &cast( + createStorageLocation(ThisPointeeType)); if (Value *ThisPointeeVal = createValue(ThisPointeeType)) setValue(*ThisPointeeLoc, *ThisPointeeVal); } @@ -327,7 +328,8 @@ Environment Environment::pushCall(const CallExpr *Call) const { if (const auto *MethodCall = dyn_cast(Call)) { if (const Expr *Arg = MethodCall->getImplicitObjectArgument()) { if (!isa(Arg)) -Env.ThisPointeeLoc = getStorageLocation(*Arg, SkipPast::Reference); +Env.ThisPointeeLoc = cast( +getStorageLocation(*Arg, SkipPast::Reference)); // Otherwise (when the argument is `this`), retain the current // environment's `ThisPointeeLoc`. } @@ -342,7 +344,8 @@ Environment Environment::pushCall(const CallExpr *Call) const { Environment Environment::pushCall(const CXXConstructExpr *Call) const { Environment Env(*this); - Env.ThisPointeeLoc = &Env.createStorageLocation(Call->getType()); + Env.ThisPointeeLoc = &cast( + Env.createStorageLocation(Call->getType())); if (Value *Val = Env.createValue(Call->getType())) Env.setValue(*Env.ThisPointeeLoc, *Val); @@ -685,7 +688,7 @@ StorageLocation *Environment::getStorageLocationStrict(const Expr &E) const { return Loc; } -StorageLocation *Environment::getThisPointeeStorageLocation() const { +AggregateStorageLocation *Environment::getThisPointeeStorageLocation() const { return ThisPointeeLoc; } diff --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp index 99f18a07ed65c4..d2908725d79b3d 100644 --- a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp +++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp @@ -366,8 +366,7 @@ builtinTransferInitializer(const CFGInitializer &Elt, assert(Init != nullptr); auto &Env = InputState.Env; - auto &ThisLoc = - *cast(Env.getThisPointeeStorageLocation()); + auto &ThisLoc = *Env.getThisPointeeStorageLocation(); if (!Init->isAnyMemberInitializer()) // FIXME: Handle base
[clang] d363248 - [clang][dataflow] Initialize fields of anonymous records correctly.
Author: Martin Braenne Date: 2023-06-29T04:07:04Z New Revision: d36324866ee1fb4d1c26552b6b686a463d2b448f URL: https://github.com/llvm/llvm-project/commit/d36324866ee1fb4d1c26552b6b686a463d2b448f DIFF: https://github.com/llvm/llvm-project/commit/d36324866ee1fb4d1c26552b6b686a463d2b448f.diff LOG: [clang][dataflow] Initialize fields of anonymous records correctly. Previously, the newly added test would crash. Depends On D153851 Reviewed By: gribozavr2 Differential Revision: https://reviews.llvm.org/D153852 Added: Modified: clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index 44801a41c10fa..f4867c4becea0 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -227,8 +227,12 @@ void Environment::initFieldsGlobalsAndFuncs(const FunctionDecl *FuncDecl) { // constructor-initializers. if (const auto *CtorDecl = dyn_cast(FuncDecl)) { for (const auto *Init : CtorDecl->inits()) { - if (const auto *M = Init->getAnyMember()) - Fields.insert(M); + if (Init->isMemberInitializer()) { +Fields.insert(Init->getMember()); + } else if (Init->isIndirectMemberInitializer()) { +for (const auto *I : Init->getIndirectMember()->chain()) + Fields.insert(cast(I)); + } const Expr *E = Init->getInit(); assert(E != nullptr); getFieldsGlobalsAndFuncs(*E, Fields, Vars, Funcs); diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp index 54b8b3a108dc0..651930f0dd22b 100644 --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -153,7 +153,7 @@ static void propagateStorageLocation(const Expr &From, const Expr &To, Env.setStorageLocationStrict(To, *Loc); } -// Forwards the value or storage location of `From` to `To` in cases where +// Propagates the value or storage location of `From` to `To` in cases where // `From` may be either a glvalue or a prvalue. `To` must be a glvalue iff // `From` is a glvalue. static void propagateValueOrStorageLocation(const Expr &From, const Expr &To, @@ -572,18 +572,7 @@ class TransferVisitor : public ConstStmtVisitor { void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *S) { const Expr *InitExpr = S->getExpr(); assert(InitExpr != nullptr); - -Value *InitExprVal = Env.getValue(*InitExpr, SkipPast::None); -if (InitExprVal == nullptr) - return; - -const FieldDecl *Field = S->getField(); -assert(Field != nullptr); - -auto &ThisLoc = -*cast(Env.getThisPointeeStorageLocation()); -auto &FieldLoc = ThisLoc.getChild(*Field); -Env.setValue(FieldLoc, *InitExprVal); +propagateValueOrStorageLocation(*InitExpr, *S, Env); } void VisitCXXConstructExpr(const CXXConstructExpr *S) { diff --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp index 16f8ab9683d56..99f18a07ed65c 100644 --- a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp +++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp @@ -366,27 +366,41 @@ builtinTransferInitializer(const CFGInitializer &Elt, assert(Init != nullptr); auto &Env = InputState.Env; - const auto &ThisLoc = + auto &ThisLoc = *cast(Env.getThisPointeeStorageLocation()); - const FieldDecl *Member = Init->getMember(); - if (Member == nullptr) -// Not a field initializer. + if (!Init->isAnyMemberInitializer()) +// FIXME: Handle base initialization return; auto *InitStmt = Init->getInit(); assert(InitStmt != nullptr); + const FieldDecl *Member = nullptr; + StorageLocation *MemberLoc = nullptr; + if (Init->isMemberInitializer()) { +Member = Init->getMember(); +MemberLoc = &ThisLoc.getChild(*Member); + } else { +IndirectFieldDecl *IndirectField = Init->getIndirectMember(); +assert(IndirectField != nullptr); +MemberLoc = &ThisLoc; +for (const auto *I : IndirectField->chain()) { + Member = cast(I); + MemberLoc = &cast(MemberLoc)->getChild(*Member); +} + } + assert(Member != nullptr); + assert(MemberLoc != nullptr); + if (Member->getType()->isReferenceType()) { auto *InitStmtLoc = Env.getStorageLocationStrict(*InitStmt); if (InitStmtLoc == nullptr) return; -auto &MemberLoc = ThisLoc.getChild(*Member); -Env.setValue(MemberLoc, Env.create(*InitStmtLoc)); +Env.setValue(*MemberLoc, Env.create(*I
[clang] 1d7f9ce - [clang][dataflow] Don't crash when creating pointers to members.
Author: Martin Braenne Date: 2023-06-29T07:12:55Z New Revision: 1d7f9ce61f6e689ca63df2e36808885c873cf80b URL: https://github.com/llvm/llvm-project/commit/1d7f9ce61f6e689ca63df2e36808885c873cf80b DIFF: https://github.com/llvm/llvm-project/commit/1d7f9ce61f6e689ca63df2e36808885c873cf80b.diff LOG: [clang][dataflow] Don't crash when creating pointers to members. The newly added tests crash without the other changes in this patch. Reviewed By: sammccall, xazax.hun, gribozavr2 Differential Revision: https://reviews.llvm.org/D153960 Added: Modified: clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp index 651930f0dd22b..5ad176dc1cdbe 100644 --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -231,6 +231,15 @@ class TransferVisitor : public ConstStmtVisitor { void VisitDeclRefExpr(const DeclRefExpr *S) { const ValueDecl *VD = S->getDecl(); assert(VD != nullptr); + +// `DeclRefExpr`s to fields and non-static methods aren't glvalues, and +// there's also no sensible `Value` we can assign to them, so skip them. +if (isa(VD)) + return; +if (auto *Method = dyn_cast(VD); +Method && !Method->isStatic()) + return; + auto *DeclLoc = Env.getStorageLocation(*VD); if (DeclLoc == nullptr) return; @@ -397,8 +406,7 @@ class TransferVisitor : public ConstStmtVisitor { propagateValueOrStorageLocation(*SubExpr, *S, Env); break; } -case CK_NullToPointer: -case CK_NullToMemberPointer: { +case CK_NullToPointer: { auto &Loc = Env.createStorageLocation(S->getType()); Env.setStorageLocation(*S, Loc); @@ -407,6 +415,10 @@ class TransferVisitor : public ConstStmtVisitor { Env.setValue(Loc, NullPointerVal); break; } +case CK_NullToMemberPointer: + // FIXME: Implement pointers to members. For now, don't associate a value + // with this expression. + break; case CK_FunctionToPointerDecay: case CK_BuiltinFnToFnPtr: { StorageLocation *PointeeLoc = @@ -440,14 +452,12 @@ class TransferVisitor : public ConstStmtVisitor { break; } case UO_AddrOf: { - // Do not form a pointer to a reference. If `SubExpr` is assigned a - // `ReferenceValue` then form a value that points to the location of its - // pointee. - StorageLocation *PointeeLoc = Env.getStorageLocationStrict(*SubExpr); - if (PointeeLoc == nullptr) + // FIXME: Model pointers to members. + if (S->getType()->isMemberPointerType()) break; - Env.setValueStrict(*S, Env.create(*PointeeLoc)); + if (StorageLocation *PointeeLoc = Env.getStorageLocationStrict(*SubExpr)) +Env.setValueStrict(*S, Env.create(*PointeeLoc)); break; } case UO_LNot: { diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index 5d2a82b581f3b..210b85f7ae8d6 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -2530,10 +2530,56 @@ TEST(TransferTest, NullToPointerCast) { }); } +TEST(TransferTest, PointerToMemberVariable) { + std::string Code = R"( +struct S { + int i; +}; +void target() { + int S::*MemberPointer = &S::i; + // [[p]] +} + )"; + runDataflow( + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) { +const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); + +const ValueDecl *MemberPointerDecl = +findValueDecl(ASTCtx, "MemberPointer"); +ASSERT_THAT(MemberPointerDecl, NotNull()); +ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull()); + }); +} + +TEST(TransferTest, PointerToMemberFunction) { + std::string Code = R"( +struct S { + void Method(); +}; +void target() { + void (S::*MemberPointer)() = &S::Method; + // [[p]] +} + )"; + runDataflow( + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) { +const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); + +const ValueDecl *MemberPointerDecl = +findValueDecl(ASTCtx, "MemberPointer"); +ASSERT_THAT(MemberPointerDecl, NotNull()); +ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull()); + }); +} + TEST(TransferTest, NullToMemberPointerCast) { std::string Code = R"( struct Foo {}; -void target(Foo *Foo) { +void target() { int Foo::*MemberPointer = nullptr; // [[p]] } @@ -2548,12 +2594,7 @@ TEST(TransferTest, NullToMemberPointerCast) {
[clang] ce0ab9d - [clang][dataflow][NFC] Share code between Environment ctor and pushCallInternal().
Author: Martin Braenne Date: 2023-04-03T08:25:10Z New Revision: ce0ab9d11cec0a81c4e48645a23fa8eddea926ab URL: https://github.com/llvm/llvm-project/commit/ce0ab9d11cec0a81c4e48645a23fa8eddea926ab DIFF: https://github.com/llvm/llvm-project/commit/ce0ab9d11cec0a81c4e48645a23fa8eddea926ab.diff LOG: [clang][dataflow][NFC] Share code between Environment ctor and pushCallInternal(). The deduplicated code is moved into initVars(). As an added bonus, pushCallInternal() now also gets the "Add all fields mentioned in default member initializers" behavior, which apparently had been added to the Environment ctor but not pushCallInternal(). Reviewed By: xazax.hun, ymandel Differential Revision: https://reviews.llvm.org/D147326 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index 678e5b871cc83..b4ae172e3fa2f 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -460,8 +460,9 @@ class Environment { void pushCallInternal(const FunctionDecl *FuncDecl, ArrayRef Args); - /// Assigns storage locations and values to all variables in `Vars`. - void initVars(llvm::DenseSet Vars); + /// Assigns storage locations and values to all global variables and fields + /// referenced in `FuncDecl`. `FuncDecl` must have a body. + void initFieldsAndGlobals(const FunctionDecl *FuncDecl); // `DACtx` is not null and not owned by this object. DataflowAnalysisContext *DACtx; diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index e3bde37ea68f7..fbb8d8ab7edda 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -203,7 +203,33 @@ static void getFieldsAndGlobalVars(const Stmt &S, // FIXME: Add support for resetting globals after function calls to enable // the implementation of sound analyses. -void Environment::initVars(llvm::DenseSet Vars) { +void Environment::initFieldsAndGlobals(const FunctionDecl *FuncDecl) { + assert(FuncDecl->getBody() != nullptr); + + llvm::DenseSet Fields; + llvm::DenseSet Vars; + + // Look for global variable and field references in the + // constructor-initializers. + if (const auto *CtorDecl = dyn_cast(FuncDecl)) { +for (const auto *Init : CtorDecl->inits()) { + if (const auto *M = Init->getAnyMember()) + Fields.insert(M); + const Expr *E = Init->getInit(); + assert(E != nullptr); + getFieldsAndGlobalVars(*E, Fields, Vars); +} +// Add all fields mentioned in default member initializers. +for (const FieldDecl *F : CtorDecl->getParent()->fields()) + if (const auto *I = F->getInClassInitializer()) + getFieldsAndGlobalVars(*I, Fields, Vars); + } + getFieldsAndGlobalVars(*FuncDecl->getBody(), Fields, Vars); + + // These have to be added before the lines that follow to ensure that + // `create*` work correctly for structs. + DACtx->addModeledFields(Fields); + for (const VarDecl *D : Vars) { if (getStorageLocation(*D, SkipPast::None) != nullptr) continue; @@ -239,31 +265,7 @@ Environment::Environment(DataflowAnalysisContext &DACtx, if (const auto *FuncDecl = dyn_cast(&DeclCtx)) { assert(FuncDecl->getBody() != nullptr); -llvm::DenseSet Fields; -llvm::DenseSet Vars; - -// Look for global variable and field references in the -// constructor-initializers. -if (const auto *CtorDecl = dyn_cast(&DeclCtx)) { - for (const auto *Init : CtorDecl->inits()) { -if (const auto *M = Init->getAnyMember()) - Fields.insert(M); -const Expr *E = Init->getInit(); -assert(E != nullptr); -getFieldsAndGlobalVars(*E, Fields, Vars); - } - // Add all fields mentioned in default member initializers. - for (const FieldDecl *F : CtorDecl->getParent()->fields()) -if (const auto *I = F->getInClassInitializer()) - getFieldsAndGlobalVars(*I, Fields, Vars); -} -getFieldsAndGlobalVars(*FuncDecl->getBody(), Fields, Vars); - -// These have to be added before the lines that follow to ensure that -// `create*` work correctly for structs. -DACtx.addModeledFields(Fields); - -initVars(Vars); +initFieldsAndGlobals(FuncDecl); for (const auto *ParamDecl : FuncDecl->parameters()) { assert(ParamDecl != nullptr); @@ -337,26 +339,7 @@ void Environment::pushCallInternal(const FunctionDecl *FuncDecl, ArrayRef Args) { CallStack.push_back(FuncDecl);
[clang] 745a957 - [clang][dataflow] Add `create()` methods to `Environment` and `DataflowAnalysisContext`.
Author: Martin Braenne Date: 2023-04-04T07:13:44Z New Revision: 745a957f9dc562477cbe587fb3fa8305713b51b3 URL: https://github.com/llvm/llvm-project/commit/745a957f9dc562477cbe587fb3fa8305713b51b3 DIFF: https://github.com/llvm/llvm-project/commit/745a957f9dc562477cbe587fb3fa8305713b51b3.diff LOG: [clang][dataflow] Add `create()` methods to `Environment` and `DataflowAnalysisContext`. These methods provide a less verbose way of allocating `StorageLocation`s and `Value`s than the existing `takeOwnership(make_unique(...))` pattern. In addition, because allocation of `StorageLocation`s and `Value`s now happens within the `DataflowAnalysisContext`, the `create()` open up the possibility of using `BumpPtrAllocator` to allocate these objects if it turns out this helps performance. Reviewed By: ymandel, xazax.hun, gribozavr2 Differential Revision: https://reviews.llvm.org/D147302 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h index a044f477ce1b..31bd9809a72a 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h @@ -86,14 +86,51 @@ class DataflowAnalysisContext { /*Logger=*/nullptr}); ~DataflowAnalysisContext(); + /// Creates a `T` (some subclass of `StorageLocation`), forwarding `args` to + /// the constructor, and returns a reference to it. + /// + /// The `DataflowAnalysisContext` takes ownership of the created object. The + /// object will be destroyed when the `DataflowAnalysisContext` is destroyed. + template + std::enable_if_t::value, T &> + create(Args &&...args) { +// Note: If allocation of individual `StorageLocation`s turns out to be +// costly, consider creating specializations of `create` for commonly +// used `StorageLocation` subclasses and make them use a `BumpPtrAllocator`. +return *cast( +Locs.emplace_back(std::make_unique(std::forward(args)...)) +.get()); + } + + /// Creates a `T` (some subclass of `Value`), forwarding `args` to the + /// constructor, and returns a reference to it. + /// + /// The `DataflowAnalysisContext` takes ownership of the created object. The + /// object will be destroyed when the `DataflowAnalysisContext` is destroyed. + template + std::enable_if_t::value, T &> + create(Args &&...args) { +// Note: If allocation of individual `Value`s turns out to be costly, +// consider creating specializations of `create` for commonly used +// `Value` subclasses and make them use a `BumpPtrAllocator`. +return *cast( +Vals.emplace_back(std::make_unique(std::forward(args)...)) +.get()); + } + /// Takes ownership of `Loc` and returns a reference to it. /// + /// This function is deprecated. Instead of + /// `takeOwnership(std::make_unique(args))`, prefer + /// `create(args)`. + /// /// Requirements: /// /// `Loc` must not be null. template - std::enable_if_t::value, T &> - takeOwnership(std::unique_ptr Loc) { + LLVM_DEPRECATED("use create instead", "") + std::enable_if_t::value, + T &> takeOwnership(std::unique_ptr Loc) { assert(Loc != nullptr); Locs.push_back(std::move(Loc)); return *cast(Locs.back().get()); @@ -101,12 +138,17 @@ class DataflowAnalysisContext { /// Takes ownership of `Val` and returns a reference to it. /// + /// This function is deprecated. Instead of + /// `takeOwnership(std::make_unique(args))`, prefer + /// `create(args)`. + /// /// Requirements: /// /// `Val` must not be null. template - std::enable_if_t::value, T &> - takeOwnership(std::unique_ptr Val) { + LLVM_DEPRECATED("use create instead", "") + std::enable_if_t::value, T &> takeOwnership( + std::unique_ptr Val) { assert(Val != nullptr); Vals.push_back(std::move(Val)); return *cast(Vals.back().get()); @@ -170,9 +212,9 @@ class DataflowAnalysisContext { } /// Creates an atomic boolean value. - AtomicBoolValue &createAtomicBoolValue() { -return takeOwnership(std::make_unique()); - } + LLVM_DEPRECATED("use create instead", + "create") + AtomicBoolValue &createAtomicBoolValue() { return create(); } /// Creates a Top value for booleans. Each instance i
[clang] 3c8ead2 - [clang][dataflow] Eliminate code duplication in Environment::createValueUnlessSelfReferential().
Author: Martin Braenne Date: 2023-04-06T07:01:44Z New Revision: 3c8ead2662ac4a223467007c340c9f9a4b2b38af URL: https://github.com/llvm/llvm-project/commit/3c8ead2662ac4a223467007c340c9f9a4b2b38af DIFF: https://github.com/llvm/llvm-project/commit/3c8ead2662ac4a223467007c340c9f9a4b2b38af.diff LOG: [clang][dataflow] Eliminate code duplication in Environment::createValueUnlessSelfReferential(). Reviewed By: sammccall Differential Revision: https://reviews.llvm.org/D147601 Added: Modified: clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index faeabdcbeed66..ee8f6c5b8f574 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -688,9 +688,9 @@ Value *Environment::createValueUnlessSelfReferential( return &create(); } - if (Type->isReferenceType()) { + if (Type->isReferenceType() || Type->isPointerType()) { CreatedValuesCount++; -QualType PointeeType = Type->castAs()->getPointeeType(); +QualType PointeeType = Type->getPointeeType(); auto &PointeeLoc = createStorageLocation(PointeeType); if (Visited.insert(PointeeType.getCanonicalType()).second) { @@ -702,24 +702,10 @@ Value *Environment::createValueUnlessSelfReferential( setValue(PointeeLoc, *PointeeVal); } -return &create(PointeeLoc); - } - - if (Type->isPointerType()) { -CreatedValuesCount++; -QualType PointeeType = Type->castAs()->getPointeeType(); -auto &PointeeLoc = createStorageLocation(PointeeType); - -if (Visited.insert(PointeeType.getCanonicalType()).second) { - Value *PointeeVal = createValueUnlessSelfReferential( - PointeeType, Visited, Depth, CreatedValuesCount); - Visited.erase(PointeeType.getCanonicalType()); - - if (PointeeVal != nullptr) -setValue(PointeeLoc, *PointeeVal); -} - -return &create(PointeeLoc); +if (Type->isReferenceType()) + return &create(PointeeLoc); +else + return &create(PointeeLoc); } if (Type->isStructureOrClassType() || Type->isUnionType()) { ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] effdfa7 - [clang][dataflow] Use `isRecordType()` where appropriate.
Author: Martin Braenne Date: 2023-04-06T07:26:24Z New Revision: effdfa7d5f49b00b4c0d36f7c6835b519b0f46bb URL: https://github.com/llvm/llvm-project/commit/effdfa7d5f49b00b4c0d36f7c6835b519b0f46bb DIFF: https://github.com/llvm/llvm-project/commit/effdfa7d5f49b00b4c0d36f7c6835b519b0f46bb.diff LOG: [clang][dataflow] Use `isRecordType()` where appropriate. This is less verbose than checking for class, struct, and union individually, and I believe it's also more efficient (not that that should be the overriding concern). Reviewed By: sammccall, xazax.hun Differential Revision: https://reviews.llvm.org/D147603 Added: Modified: clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp index 4d8a42c1390c2..1fbc3759747e8 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp @@ -45,8 +45,7 @@ DataflowAnalysisContext::getReferencedFields(QualType Type) { } StorageLocation &DataflowAnalysisContext::createStorageLocation(QualType Type) { - if (!Type.isNull() && - (Type->isStructureOrClassType() || Type->isUnionType())) { + if (!Type.isNull() && Type->isRecordType()) { llvm::DenseMap FieldLocs; // During context-sensitive analysis, a struct may be allocated in one // function, but its field accessed in a function lower in the stack than diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index ee8f6c5b8f574..6a6343b5f169b 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -608,7 +608,7 @@ void Environment::setValue(const StorageLocation &Loc, Value &Val) { auto &AggregateLoc = *cast(&Loc); const QualType Type = AggregateLoc.getType(); -assert(Type->isStructureOrClassType() || Type->isUnionType()); +assert(Type->isRecordType()); for (const FieldDecl *Field : DACtx->getReferencedFields(Type)) { assert(Field != nullptr); @@ -708,7 +708,7 @@ Value *Environment::createValueUnlessSelfReferential( return &create(PointeeLoc); } - if (Type->isStructureOrClassType() || Type->isUnionType()) { + if (Type->isRecordType()) { CreatedValuesCount++; llvm::DenseMap FieldValues; for (const FieldDecl *Field : DACtx->getReferencedFields(Type)) { ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 991c7e1 - [clang][dataflow][NFC] Remove unused parameter from `insertIfGlobal()`.
Author: Martin Braenne Date: 2023-04-11T11:31:56Z New Revision: 991c7e11728f6f6372e5dc865e3a4c0636a575ea URL: https://github.com/llvm/llvm-project/commit/991c7e11728f6f6372e5dc865e3a4c0636a575ea DIFF: https://github.com/llvm/llvm-project/commit/991c7e11728f6f6372e5dc865e3a4c0636a575ea.diff LOG: [clang][dataflow][NFC] Remove unused parameter from `insertIfGlobal()`. Reviewed By: gribozavr2 Differential Revision: https://reviews.llvm.org/D148004 Added: Modified: clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index 6a6343b5f169b..680036b6a5b39 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -156,7 +156,6 @@ static Value &widenDistinctValues(QualType Type, Value &Prev, /// Initializes a global storage value. static void insertIfGlobal(const Decl &D, - llvm::DenseSet &Fields, llvm::DenseSet &Vars) { if (auto *V = dyn_cast(&D)) if (V->hasGlobalStorage()) @@ -166,7 +165,7 @@ static void insertIfGlobal(const Decl &D, static void getFieldsAndGlobalVars(const Decl &D, llvm::DenseSet &Fields, llvm::DenseSet &Vars) { - insertIfGlobal(D, Fields, Vars); + insertIfGlobal(D, Vars); if (const auto *Decomp = dyn_cast(&D)) for (const auto *B : Decomp->bindings()) if (auto *ME = dyn_cast_or_null(B->getBinding())) @@ -191,11 +190,11 @@ static void getFieldsAndGlobalVars(const Stmt &S, for (auto *D : DS->getDeclGroup()) getFieldsAndGlobalVars(*D, Fields, Vars); } else if (auto *E = dyn_cast(&S)) { -insertIfGlobal(*E->getDecl(), Fields, Vars); +insertIfGlobal(*E->getDecl(), Vars); } else if (auto *E = dyn_cast(&S)) { // FIXME: should we be using `E->getFoundDecl()`? const ValueDecl *VD = E->getMemberDecl(); -insertIfGlobal(*VD, Fields, Vars); +insertIfGlobal(*VD, Vars); if (const auto *FD = dyn_cast(VD)) Fields.insert(FD); } ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 5a16665 - [clang][dataflow] Use `Strict` accessors in more places in Transfer.cpp.
Author: Martin Braenne Date: 2023-05-22T06:51:10Z New Revision: 5a16665ed53500b7ee6703be3d5b9e0bca6f1c14 URL: https://github.com/llvm/llvm-project/commit/5a16665ed53500b7ee6703be3d5b9e0bca6f1c14 DIFF: https://github.com/llvm/llvm-project/commit/5a16665ed53500b7ee6703be3d5b9e0bca6f1c14.diff LOG: [clang][dataflow] Use `Strict` accessors in more places in Transfer.cpp. This patch handles the straightforward cases. Upcoming separate patches will handle the cases that are more subtle. This patch is part of the ongoing migration to strict handling of value categories (see https://discourse.llvm.org/t/70086 for details). Depends On D150653 Reviewed By: sammccall, ymandel, xazax.hun Differential Revision: https://reviews.llvm.org/D150655 Added: Modified: clang/lib/Analysis/FlowSensitive/Transfer.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp index 45c601ed49146..838ad934b5fbd 100644 --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -48,10 +48,8 @@ const Environment *StmtToEnvMap::getEnvironment(const Stmt &S) const { static BoolValue &evaluateBooleanEquality(const Expr &LHS, const Expr &RHS, Environment &Env) { - if (auto *LHSValue = - dyn_cast_or_null(Env.getValue(LHS, SkipPast::Reference))) -if (auto *RHSValue = -dyn_cast_or_null(Env.getValue(RHS, SkipPast::Reference))) + if (auto *LHSValue = dyn_cast_or_null(Env.getValueStrict(LHS))) +if (auto *RHSValue = dyn_cast_or_null(Env.getValueStrict(RHS))) return Env.makeIff(*LHSValue, *RHSValue); return Env.makeAtomicBoolValue(); @@ -121,9 +119,7 @@ static BoolValue &unpackValue(BoolValue &V, Environment &Env) { // value, if any unpacking occured. Also, does the lvalue-to-rvalue conversion, // by skipping past the reference. static Value *maybeUnpackLValueExpr(const Expr &E, Environment &Env) { - // FIXME: this is too flexible: it _allows_ a reference, while it should - // _require_ one, since lvalues should always be wrapped in `ReferenceValue`. - auto *Loc = Env.getStorageLocation(E, SkipPast::Reference); + auto *Loc = Env.getStorageLocationStrict(E); if (Loc == nullptr) return nullptr; auto *Val = Env.getValue(*Loc); @@ -139,6 +135,29 @@ static Value *maybeUnpackLValueExpr(const Expr &E, Environment &Env) { return &UnpackedVal; } +static void propagateValue(const Expr &From, const Expr &To, Environment &Env) { + if (auto *Val = Env.getValueStrict(From)) +Env.setValueStrict(To, *Val); +} + +static void propagateStorageLocation(const Expr &From, const Expr &To, + Environment &Env) { + if (auto *Loc = Env.getStorageLocationStrict(From)) +Env.setStorageLocationStrict(To, *Loc); +} + +// Forwards the value or storage location of `From` to `To` in cases where +// `From` may be either a glvalue or a prvalue. `To` must be a glvalue iff +// `From` is a glvalue. +static void propagateValueOrStorageLocation(const Expr &From, const Expr &To, +Environment &Env) { + assert(From.isGLValue() == To.isGLValue()); + if (From.isGLValue()) +propagateStorageLocation(From, To, Env); + else +propagateValue(From, To, Env); +} + namespace { class TransferVisitor : public ConstStmtVisitor { @@ -155,13 +174,11 @@ class TransferVisitor : public ConstStmtVisitor { switch (S->getOpcode()) { case BO_Assign: { - auto *LHSLoc = Env.getStorageLocation(*LHS, SkipPast::Reference); + auto *LHSLoc = Env.getStorageLocationStrict(*LHS); if (LHSLoc == nullptr) break; - // No skipping should be necessary, because any lvalues should have - // already been stripped off in evaluating the LValueToRValue cast. - auto *RHSVal = Env.getValue(*RHS, SkipPast::None); + auto *RHSVal = Env.getValueStrict(*RHS); if (RHSVal == nullptr) break; @@ -276,7 +293,7 @@ class TransferVisitor : public ConstStmtVisitor { return; } - if (auto *InitExprVal = Env.getValue(*InitExpr, SkipPast::None)) + if (auto *InitExprVal = Env.getValueStrict(*InitExpr)) Env.setValue(Loc, *InitExprVal); if (Env.getValue(Loc) == nullptr) { @@ -443,7 +460,7 @@ class TransferVisitor : public ConstStmtVisitor { } case UO_LNot: { auto *SubExprVal = - dyn_cast_or_null(Env.getValue(*SubExpr, SkipPast::None)); + dyn_cast_or_null(Env.getValueStrict(*SubExpr)); if (SubExprVal == nullptr) break; @@ -653,19 +670,13 @@ class TransferVisitor : public ConstStmtVisitor { const Expr *SubExpr = S->getSubExpr(); assert(SubExpr != nullptr); - auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
[clang] 96b22e1 - [clang][dataflow] Use `Strict` accessors in SignAnalysisTest.cpp.
Author: Martin Braenne Date: 2023-05-22T06:51:13Z New Revision: 96b22e1c378a93a26cd8fc8051bfc7b90f65b665 URL: https://github.com/llvm/llvm-project/commit/96b22e1c378a93a26cd8fc8051bfc7b90f65b665 DIFF: https://github.com/llvm/llvm-project/commit/96b22e1c378a93a26cd8fc8051bfc7b90f65b665.diff LOG: [clang][dataflow] Use `Strict` accessors in SignAnalysisTest.cpp. This patch is part of the ongoing migration to strict handling of value categories (see https://discourse.llvm.org/t/70086 for details). Depends On D150656 Reviewed By: sammccall, ymandel, xazax.hun Differential Revision: https://reviews.llvm.org/D150657 Added: Modified: clang/unittests/Analysis/FlowSensitive/SignAnalysisTest.cpp Removed: diff --git a/clang/unittests/Analysis/FlowSensitive/SignAnalysisTest.cpp b/clang/unittests/Analysis/FlowSensitive/SignAnalysisTest.cpp index 325ffe1af9914..fe4fdda888bf5 100644 --- a/clang/unittests/Analysis/FlowSensitive/SignAnalysisTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/SignAnalysisTest.cpp @@ -114,12 +114,10 @@ getValueAndSignProperties(const UnaryOperator *UO, return {nullptr, {}, {}}; // Value of the unary op. - auto *UnaryOpValue = State.Env.getValue(*UO, SkipPast::None); + auto *UnaryOpValue = State.Env.getValueStrict(*UO); if (!UnaryOpValue) { -auto &Loc = State.Env.createStorageLocation(*UO); -State.Env.setStorageLocation(*UO, Loc); UnaryOpValue = &State.Env.makeAtomicBoolValue(); -State.Env.setValue(Loc, *UnaryOpValue); +State.Env.setValueStrict(*UO, *UnaryOpValue); } // Properties for the operand (sub expression). @@ -133,22 +131,17 @@ getValueAndSignProperties(const UnaryOperator *UO, void transferBinary(const BinaryOperator *BO, const MatchFinder::MatchResult &M, LatticeTransferState &State) { - StorageLocation *Loc = State.Env.getStorageLocation(*BO, SkipPast::None); - if (!Loc) { -Loc = &State.Env.createStorageLocation(*BO); -State.Env.setStorageLocation(*BO, *Loc); - } - BoolValue *Comp = cast_or_null(State.Env.getValue(*Loc)); + BoolValue *Comp = cast_or_null(State.Env.getValueStrict(*BO)); if (!Comp) { Comp = &State.Env.makeAtomicBoolValue(); -State.Env.setValue(*Loc, *Comp); +State.Env.setValueStrict(*BO, *Comp); } // FIXME Use this as well: // auto *NegatedComp = &State.Env.makeNot(*Comp); - auto *LHS = State.Env.getValue(*BO->getLHS(), SkipPast::None); - auto *RHS = State.Env.getValue(*BO->getRHS(), SkipPast::None); + auto *LHS = State.Env.getValueStrict(*BO->getLHS()); + auto *RHS = State.Env.getValueStrict(*BO->getRHS()); if (!LHS || !RHS) return; @@ -244,19 +237,43 @@ void transferUnaryNot(const UnaryOperator *UO, } } +// Returns the `Value` associated with `E` (which may be either a prvalue or +// glvalue). Creates a `Value` or `StorageLocation` as needed if `E` does not +// have either of these associated with it yet. +// +// If this functionality turns out to be needed in more cases, this function +// should be moved to a more central location. +Value *getOrCreateValue(const Expr *E, Environment &Env) { + Value *Val = nullptr; + if (E->isGLValue()) { +StorageLocation *Loc = Env.getStorageLocationStrict(*E); +if (!Loc) { + Loc = &Env.createStorageLocation(*E); + Env.setStorageLocationStrict(*E, *Loc); +} +Val = Env.getValue(*Loc); +if (!Val) { + Val = Env.createValue(E->getType()); + Env.setValue(*Loc, *Val); +} + } else { +Val = Env.getValueStrict(*E); +if (!Val) { + Val = Env.createValue(E->getType()); + Env.setValueStrict(*E, *Val); +} + } + assert(Val != nullptr); + + return Val; +} + void transferExpr(const Expr *E, const MatchFinder::MatchResult &M, LatticeTransferState &State) { const ASTContext &Context = *M.Context; - StorageLocation *Loc = State.Env.getStorageLocation(*E, SkipPast::None); - if (!Loc) { -Loc = &State.Env.createStorageLocation(*E); -State.Env.setStorageLocation(*E, *Loc); - } - Value *Val = State.Env.getValue(*Loc); - if (!Val) { -Val = State.Env.createValue(Context.IntTy); -State.Env.setValue(*Loc, *Val); - } + + Value *Val = getOrCreateValue(E, State.Env); + // The sign symbolic values have been initialized already. if (Val->getProperty("neg")) return; ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 8bc8fc6 - [clang][dataflow] Use `Strict` accessors in TypeErasedDataflowAnalysis.cpp.
Author: Martin Braenne Date: 2023-05-22T06:51:12Z New Revision: 8bc8fc65c9b20de6ffad63d7ce6734c145265cc2 URL: https://github.com/llvm/llvm-project/commit/8bc8fc65c9b20de6ffad63d7ce6734c145265cc2 DIFF: https://github.com/llvm/llvm-project/commit/8bc8fc65c9b20de6ffad63d7ce6734c145265cc2.diff LOG: [clang][dataflow] Use `Strict` accessors in TypeErasedDataflowAnalysis.cpp. This patch is part of the ongoing migration to strict handling of value categories (see https://discourse.llvm.org/t/70086 for details). Depends On D150655 Reviewed By: sammccall, ymandel, xazax.hun Differential Revision: https://reviews.llvm.org/D150656 Added: Modified: clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp index 2e9893e78fa7..4fc8f27ffc9b 100644 --- a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp +++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp @@ -123,13 +123,10 @@ class TerminatorVisitor private: TerminatorVisitorRetTy extendFlowCondition(const Expr &Cond) { // The terminator sub-expression might not be evaluated. -if (Env.getStorageLocation(Cond, SkipPast::None) == nullptr) +if (Env.getValueStrict(Cond) == nullptr) transfer(StmtToEnv, Cond, Env); -// FIXME: The flow condition must be an r-value, so `SkipPast::None` should -// suffice. -auto *Val = -cast_or_null(Env.getValue(Cond, SkipPast::Reference)); +auto *Val = cast_or_null(Env.getValueStrict(Cond)); // Value merging depends on flow conditions from diff erent environments // being mutually exclusive -- that is, they cannot both be true in their // entirety (even if they may share some clauses). So, we need *some* value @@ -303,18 +300,14 @@ builtinTransferInitializer(const CFGInitializer &Elt, auto *InitStmt = Init->getInit(); assert(InitStmt != nullptr); - auto *InitStmtLoc = Env.getStorageLocation(*InitStmt, SkipPast::Reference); - if (InitStmtLoc == nullptr) -return; - - auto *InitStmtVal = Env.getValue(*InitStmtLoc); - if (InitStmtVal == nullptr) -return; - if (Member->getType()->isReferenceType()) { +auto *InitStmtLoc = Env.getStorageLocationStrict(*InitStmt); +if (InitStmtLoc == nullptr) + return; + auto &MemberLoc = ThisLoc.getChild(*Member); Env.setValue(MemberLoc, Env.create(*InitStmtLoc)); - } else { + } else if (auto *InitStmtVal = Env.getValueStrict(*InitStmt)) { auto &MemberLoc = ThisLoc.getChild(*Member); Env.setValue(MemberLoc, *InitStmtVal); } ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 3bc1ea5 - [clang][dataflow] Fix a bug in handling of `operator->` for optional checker.
Author: Martin Braenne Date: 2023-05-22T06:51:15Z New Revision: 3bc1ea5b0ac90e04e7b935a5d964613f8fbad4bf URL: https://github.com/llvm/llvm-project/commit/3bc1ea5b0ac90e04e7b935a5d964613f8fbad4bf DIFF: https://github.com/llvm/llvm-project/commit/3bc1ea5b0ac90e04e7b935a5d964613f8fbad4bf.diff LOG: [clang][dataflow] Fix a bug in handling of `operator->` for optional checker. Prior to this patch, `operator->` was being handled like `operator*`: It was associating a `Value` of type `T` with the expression result (where `T` is the template argument of the `optional`). This is correct for `operator*`, which returns a reference (of some flavor) to `T`, so that the result of the `CXXOperatorCallExpr` is a glvalue of type `T`. However, `operator*` returns a `T*`, so the result of the `CXXOperatorCallExpr` is a prvalue `T*`, which should therefore be associated with `PointerValue` that in turn refers to a `T`. I noticed this issue while working on the migration to strict handling of value categories (see https://discourse.llvm.org/t/70086). The current behavior also seems problematic more generally because it's plausible that the framework may at some point introduce behavior that assumes an `Expr` of pointer type is always associated with a `PointerValue`. As it turns out, this patch fixes an existing FIXME in the test `OptionalValueInitialization`. Depends On D150657 Reviewed By: ymandel Differential Revision: https://reviews.llvm.org/D150775 Added: Modified: clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp index 24a3682f438cb..7d30473ea5226 100644 --- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp +++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp @@ -399,6 +399,18 @@ void transferUnwrapCall(const Expr *UnwrapExpr, const Expr *ObjectExpr, } } +void transferArrowOpCall(const Expr *UnwrapExpr, const Expr *ObjectExpr, + LatticeTransferState &State) { + if (auto *OptionalVal = + getValueBehindPossiblePointer(*ObjectExpr, State.Env)) { +if (auto *Loc = maybeInitializeOptionalValueMember( +UnwrapExpr->getType()->getPointeeType(), *OptionalVal, State.Env)) { + State.Env.setValueStrict(*UnwrapExpr, + State.Env.create(*Loc)); +} + } +} + void transferMakeOptionalCall(const CallExpr *E, const MatchFinder::MatchResult &, LatticeTransferState &State) { @@ -774,25 +786,22 @@ auto buildTransferMatchSwitch() { transferUnwrapCall(E, E->getImplicitObjectArgument(), State); }) - // optional::operator*, optional::operator-> - // FIXME: This does something slightly strange for `operator->`. - // `transferUnwrapCall()` may create a new value of type `T` for the - // `optional`, and it associates that value with `E`. In the case of - // `operator->`, `E` is a pointer. As a result, we associate an - // expression of pointer type with a storage location of non-pointer type - // `T`. This can confound other code that expects expressions of - // pointer type to be associated with `PointerValue`s, such as the - // centrally provided accessors `getImplicitObjectLocation()` and - // `getBaseObjectLocation()`, and this is the reason we need to use our - // own 'maybeSkipPointer()` and `getValueBehindPossiblePointer()` instead - // of these accessors. - .CaseOfCFGStmt(valueOperatorCall(std::nullopt), + // optional::operator* + .CaseOfCFGStmt(isOptionalOperatorCallWithName("*"), [](const CallExpr *E, const MatchFinder::MatchResult &, LatticeTransferState &State) { transferUnwrapCall(E, E->getArg(0), State); }) + // optional::operator-> + .CaseOfCFGStmt(isOptionalOperatorCallWithName("->"), + [](const CallExpr *E, + const MatchFinder::MatchResult &, + LatticeTransferState &State) { + transferArrowOpCall(E, E->getArg(0), State); + }) + // optional::has_value .CaseOfCFGStmt( isOptionalMemberCallWithName("has_value"), diff --git a/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp b/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp index a9d235
[clang] a9e90f7 - [clang][dataflow] Fix a null pointer crash in `computeBlockInputState()`.
Author: Martin Braenne Date: 2023-05-22T12:19:55Z New Revision: a9e90f7994222dde987154ed009504afbf3c2166 URL: https://github.com/llvm/llvm-project/commit/a9e90f7994222dde987154ed009504afbf3c2166 DIFF: https://github.com/llvm/llvm-project/commit/a9e90f7994222dde987154ed009504afbf3c2166.diff LOG: [clang][dataflow] Fix a null pointer crash in `computeBlockInputState()`. The crash was due to unconditionally calling `Block.succ_begin()->getReachableBlock()->hasNoReturnElement()`, but `getReachableBlock()` can return null now that we have turned `PruneTriviallyFalseEdges` on. This patch adds two tests that crash without the fix. Reviewed By: ymandel Differential Revision: https://reviews.llvm.org/D151071 Added: Modified: clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp index 4fc8f27ffc9b2..37dd7081ae986 100644 --- a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp +++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp @@ -216,7 +216,8 @@ computeBlockInputState(const CFGBlock &Block, AnalysisContext &AC) { // operator includes a branch that contains a noreturn destructor call. // // See `NoreturnDestructorTest` for concrete examples. -if (Block.succ_begin()->getReachableBlock()->hasNoReturnElement()) { +if (Block.succ_begin()->getReachableBlock() != nullptr && +Block.succ_begin()->getReachableBlock()->hasNoReturnElement()) { auto &StmtToBlock = AC.CFCtx.getStmtToBlock(); auto StmtBlock = StmtToBlock.find(Block.getTerminatorStmt()); assert(StmtBlock != StmtToBlock.end()); diff --git a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp index 30aef86e7a26e..5bfb9e53778b0 100644 --- a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp @@ -296,6 +296,22 @@ TEST_F(NoreturnDestructorTest, ConditionalOperatorLeftBranchReturns) { UnorderedElementsAre("foo")); } +TEST_F(NoreturnDestructorTest, + ConditionalOperatorConstantCondition_LeftBranchReturns) { + std::string Code = R"( +#include "noreturn_destructor_test_defs.h" + +void target() { + int value = true ? foo() : Fatal().bar(); + (void)0; + // [[p]] +} + )"; + runDataflow(Code, UnorderedElementsAre(IsStringMapEntry( +"p", HoldsFunctionCallLattice(HasCalledFunctions( + UnorderedElementsAre("foo")); +} + TEST_F(NoreturnDestructorTest, ConditionalOperatorRightBranchReturns) { std::string Code = R"( #include "noreturn_destructor_test_defs.h" @@ -311,6 +327,22 @@ TEST_F(NoreturnDestructorTest, ConditionalOperatorRightBranchReturns) { UnorderedElementsAre("foo")); } +TEST_F(NoreturnDestructorTest, + ConditionalOperatorConstantCondition_RightBranchReturns) { + std::string Code = R"( +#include "noreturn_destructor_test_defs.h" + +void target() { + int value = false ? Fatal().bar() : foo(); + (void)0; + // [[p]] +} + )"; + runDataflow(Code, UnorderedElementsAre(IsStringMapEntry( +"p", HoldsFunctionCallLattice(HasCalledFunctions( + UnorderedElementsAre("foo")); +} + TEST_F(NoreturnDestructorTest, ConditionalOperatorNestedBranchesDoNotReturn) { std::string Code = R"( #include "noreturn_destructor_test_defs.h" ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 68baaca - [clang][dataflow] Use `Strict` accessors in comma operator and no-op cast.
Author: Martin Braenne Date: 2023-05-23T11:58:00Z New Revision: 68baaca61dfad1179a61d99cbf0fe23a6894849d URL: https://github.com/llvm/llvm-project/commit/68baaca61dfad1179a61d99cbf0fe23a6894849d DIFF: https://github.com/llvm/llvm-project/commit/68baaca61dfad1179a61d99cbf0fe23a6894849d.diff LOG: [clang][dataflow] Use `Strict` accessors in comma operator and no-op cast. This patch is part of the ongoing migration to strict handling of value categories (see https://discourse.llvm.org/t/70086 for details). Depends On D150775 Reviewed By: gribozavr2 Differential Revision: https://reviews.llvm.org/D150776 Added: Modified: clang/lib/Analysis/FlowSensitive/Transfer.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp index 838ad934b5fbd..9658f5bcd6a0e 100644 --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -224,8 +224,7 @@ class TransferVisitor : public ConstStmtVisitor { break; } case BO_Comma: { - if (auto *Loc = Env.getStorageLocation(*RHS, SkipPast::None)) -Env.setStorageLocation(*S, *Loc); + propagateValueOrStorageLocation(*RHS, *S, Env); break; } default: @@ -397,13 +396,9 @@ class TransferVisitor : public ConstStmtVisitor { // CK_ConstructorConversion, and CK_UserDefinedConversion. case CK_NoOp: { // FIXME: Consider making `Environment::getStorageLocation` skip noop - // expressions (this and other similar expressions in the file) instead of - // assigning them storage locations. - auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None); - if (SubExprLoc == nullptr) -break; - - Env.setStorageLocation(*S, *SubExprLoc); + // expressions (this and other similar expressions in the file) instead + // of assigning them storage locations. + propagateValueOrStorageLocation(*SubExpr, *S, Env); break; } case CK_NullToPointer: ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 246626a - [clang][dataflow] Add a `ControlFlowContext::build()` overload taking a `FunctionDecl`.
Author: Martin Braenne Date: 2023-05-25T07:19:12Z New Revision: 246626a8cfd3d4f910baadeff4d5aa544b9d4550 URL: https://github.com/llvm/llvm-project/commit/246626a8cfd3d4f910baadeff4d5aa544b9d4550 DIFF: https://github.com/llvm/llvm-project/commit/246626a8cfd3d4f910baadeff4d5aa544b9d4550.diff LOG: [clang][dataflow] Add a `ControlFlowContext::build()` overload taking a `FunctionDecl`. This is the most common use case, so it makes sense to have a specific overload for it. Reviewed By: xazax.hun Differential Revision: https://reviews.llvm.org/D151183 Added: Modified: clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp clang/unittests/Analysis/FlowSensitive/TestingSupport.h clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h b/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h index b51e2cb23634d..f327011766069 100644 --- a/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h +++ b/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h @@ -31,6 +31,11 @@ namespace dataflow { /// analysis. class ControlFlowContext { public: + /// Builds a ControlFlowContext from a `FunctionDecl`. + /// `Func.hasBody()` must be true, and `Func.isTemplated()` must be false. + static llvm::Expected build(const FunctionDecl &Func, + ASTContext &C); + /// Builds a ControlFlowContext from an AST node. `D` is the function in which /// `S` resides. `D.isTemplated()` must be false. static llvm::Expected build(const Decl &D, Stmt &S, diff --git a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp index 4556787d10a8e..c62bff33524cf 100644 --- a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp +++ b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp @@ -67,6 +67,16 @@ static llvm::BitVector findReachableBlocks(const CFG &Cfg) { return BlockReachable; } +llvm::Expected +ControlFlowContext::build(const FunctionDecl &Func, ASTContext &C) { + if (!Func.hasBody()) +return llvm::createStringError( +std::make_error_code(std::errc::invalid_argument), +"Cannot analyze function without a body"); + + return build(Func, *Func.getBody(), C); +} + llvm::Expected ControlFlowContext::build(const Decl &D, Stmt &S, ASTContext &C) { if (D.isTemplated()) diff --git a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp index 73428ac250ad3..32612397ec024 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp @@ -210,8 +210,8 @@ DataflowAnalysisContext::getControlFlowContext(const FunctionDecl *F) { if (It != FunctionContexts.end()) return &It->second; - if (Stmt *Body = F->getBody()) { -auto CFCtx = ControlFlowContext::build(*F, *Body, F->getASTContext()); + if (F->hasBody()) { +auto CFCtx = ControlFlowContext::build(*F, F->getASTContext()); // FIXME: Handle errors. assert(CFCtx); auto Result = FunctionContexts.insert({F, std::move(*CFCtx)}); diff --git a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h index ff7d27d6540cc..d5591bee12dc2 100644 --- a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h +++ b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h @@ -241,8 +241,7 @@ checkDataflow(AnalysisInputs AI, llvm::errc::invalid_argument, "Could not find the target function."); // Build the control flow graph for the target function. -auto MaybeCFCtx = -ControlFlowContext::build(*Target, *Target->getBody(), Context); +auto MaybeCFCtx = ControlFlowContext::build(*Target, Context); if (!MaybeCFCtx) return MaybeCFCtx.takeError(); auto &CFCtx = *MaybeCFCtx; diff --git a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp index 5bfb9e53778b0..84b10c87f6b19 100644 --- a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp @@ -67,8 +67,8 @@ runAnalysis(llvm::StringRef Code, AnalysisT (*MakeAnalysis)(ASTContext &)) { Stmt *Body = Func->getBody(); assert(Body != nullptr); - auto CFCtx = llvm::cantFail( - ControlFlowContext::build(*Func, *Body, AST->getASTContext())); + auto CFCtx = + llvm::cantFail(ControlFlowContext::build(*Func, AST->getASTContext())); AnalysisT Anal
[clang] 6441358 - [clang][dataflow] Add support for return values of reference type.
Author: Martin Braenne Date: 2023-05-25T08:38:33Z New Revision: 64413584dacba1fccffa345f69043b3509ee1745 URL: https://github.com/llvm/llvm-project/commit/64413584dacba1fccffa345f69043b3509ee1745 DIFF: https://github.com/llvm/llvm-project/commit/64413584dacba1fccffa345f69043b3509ee1745.diff LOG: [clang][dataflow] Add support for return values of reference type. This patch changes the way `Environment::ReturnLoc` is set: Whereas previously it was set by the caller, it is now set by the callee (obviously, as we otherwise would not be able to return references). The patch also introduces `Environment::ReturnVal`, which is used for non-reference-type return values. This allows these to be handled with the correct value category semantics; see also https://discourse.llvm.org/t/70086, which describes the ongoing migration to strict value category semantics. Depends On D150776 Reviewed By: ymandel, xazax.hun Differential Revision: https://reviews.llvm.org/D151194 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index 6f2f7f4004f84..a31f5ec116425 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -192,7 +192,8 @@ class Environment { /// Moves gathered information back into `this` from a `CalleeEnv` created via /// `pushCall`. - void popCall(const Environment &CalleeEnv); + void popCall(const CallExpr *Call, const Environment &CalleeEnv); + void popCall(const CXXConstructExpr *Call, const Environment &CalleeEnv); /// Returns true if and only if the environment is equivalent to `Other`, i.e /// the two environments: @@ -323,8 +324,51 @@ class Environment { /// in the environment. StorageLocation *getThisPointeeStorageLocation() const; - /// Returns the storage location of the return value or null, if unset. - StorageLocation *getReturnStorageLocation() const; + /// Returns the return value of the current function. This can be null if: + /// - The function has a void return type + /// - No return value could be determined for the function, for example + /// because it calls a function without a body. + /// + /// Requirements: + /// The current function must have a non-reference return type. + Value *getReturnValue() const { +assert(getCurrentFunc() != nullptr && + !getCurrentFunc()->getReturnType()->isReferenceType()); +return ReturnVal; + } + + /// Returns the storage location for the reference returned by the current + /// function. This can be null if function doesn't return a single consistent + /// reference. + /// + /// Requirements: + /// The current function must have a reference return type. + StorageLocation *getReturnStorageLocation() const { +assert(getCurrentFunc() != nullptr && + getCurrentFunc()->getReturnType()->isReferenceType()); +return ReturnLoc; + } + + /// Sets the return value of the current function. + /// + /// Requirements: + /// The current function must have a non-reference return type. + void setReturnValue(Value *Val) { +assert(getCurrentFunc() != nullptr && + !getCurrentFunc()->getReturnType()->isReferenceType()); +ReturnVal = Val; + } + + /// Sets the storage location for the reference returned by the current + /// function. + /// + /// Requirements: + /// The current function must have a reference return type. + void setReturnStorageLocation(StorageLocation *Loc) { +assert(getCurrentFunc() != nullptr && + getCurrentFunc()->getReturnType()->isReferenceType()); +ReturnLoc = Loc; + } /// Returns a pointer value that represents a null pointer. Calls with /// `PointeeType` that are canonically equivalent will return the same result. @@ -472,6 +516,12 @@ class Environment { /// returns null. const DeclContext *getDeclCtx() const { return CallStack.back(); } + /// Returns the function currently being analyzed, or null if the code being + /// analyzed isn't part of a function. + const FunctionDecl *getCurrentFunc() const { +return dyn_cast(getDeclCtx()); + } + /// Returns whether this `Environment` can be extended to analyze the given /// `Callee` (i.e. if `pushCall` can be used), with recursion disallowed and a /// given `MaxDepth`. @@ -515,16 +565,18 @@ class Environment { // `DACtx` is not null and not owned by this object. DataflowAnalysisContext *DACtx; - - // FIXME: move the fields `CallStack`, `ReturnLoc` and `ThisPointeeLoc` into a - //
[clang] 49946df - [clang][dataflow][NFC] Remove unused variable.
Author: Martin Braenne Date: 2023-05-25T12:09:52Z New Revision: 49946df8211e9d36f0b3755e64b55bc28c0a4247 URL: https://github.com/llvm/llvm-project/commit/49946df8211e9d36f0b3755e64b55bc28c0a4247 DIFF: https://github.com/llvm/llvm-project/commit/49946df8211e9d36f0b3755e64b55bc28c0a4247.diff LOG: [clang][dataflow][NFC] Remove unused variable. Thanks to chapuni to pointing this out on https://reviews.llvm.org/D151183. Differential Revision: https://reviews.llvm.org/D151430 Added: Modified: clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp Removed: diff --git a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp index 84b10c87f6b1..1d94b69cfce8 100644 --- a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp @@ -64,9 +64,6 @@ runAnalysis(llvm::StringRef Code, AnalysisT (*MakeAnalysis)(ASTContext &)) { AST->getASTContext())); assert(Func != nullptr); - Stmt *Body = Func->getBody(); - assert(Body != nullptr); - auto CFCtx = llvm::cantFail(ControlFlowContext::build(*Func, AST->getASTContext())); ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 7f6c3a9 - [clang][dataflow] Fix a crash in `getLogicOperatorSubExprValue()`.
Author: Martin Braenne Date: 2023-05-25T14:47:03Z New Revision: 7f6c3a9033b6409ada46609f5f4b650e8556f56d URL: https://github.com/llvm/llvm-project/commit/7f6c3a9033b6409ada46609f5f4b650e8556f56d DIFF: https://github.com/llvm/llvm-project/commit/7f6c3a9033b6409ada46609f5f4b650e8556f56d.diff LOG: [clang][dataflow] Fix a crash in `getLogicOperatorSubExprValue()`. This patch adds a test that crashes without the fix. Reviewed By: ymandel Differential Revision: https://reviews.llvm.org/D151201 Added: Modified: clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp index a67f9ceed82e..8547e5049261 100644 --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -194,24 +194,13 @@ class TransferVisitor : public ConstStmtVisitor { auto &Loc = Env.createStorageLocation(*S); Env.setStorageLocation(*S, Loc); - BoolValue *LHSVal = getLogicOperatorSubExprValue(*LHS); - // If the LHS was not reachable, this BinaryOperator would also not be - // reachable, and we would never get here. - assert(LHSVal != nullptr); - BoolValue *RHSVal = getLogicOperatorSubExprValue(*RHS); - if (RHSVal == nullptr) { -// If the RHS isn't reachable and we evaluate this BinaryOperator, -// then the value of the LHS must have triggered the short-circuit -// logic. This implies that the value of the entire expression must be -// equal to the value of the LHS. -Env.setValue(Loc, *LHSVal); -break; - } + BoolValue &LHSVal = getLogicOperatorSubExprValue(*LHS); + BoolValue &RHSVal = getLogicOperatorSubExprValue(*RHS); if (S->getOpcode() == BO_LAnd) -Env.setValue(Loc, Env.makeAnd(*LHSVal, *RHSVal)); +Env.setValue(Loc, Env.makeAnd(LHSVal, RHSVal)); else -Env.setValue(Loc, Env.makeOr(*LHSVal, *RHSVal)); +Env.setValue(Loc, Env.makeOr(LHSVal, RHSVal)); break; } case BO_NE: @@ -805,35 +794,29 @@ class TransferVisitor : public ConstStmtVisitor { } private: - /// If `SubExpr` is reachable, returns a non-null pointer to the value for - /// `SubExpr`. If `SubExpr` is not reachable, returns nullptr. - BoolValue *getLogicOperatorSubExprValue(const Expr &SubExpr) { + /// Returns the value for the sub-expression `SubExpr` of a logic operator. + BoolValue &getLogicOperatorSubExprValue(const Expr &SubExpr) { // `SubExpr` and its parent logic operator might be part of diff erent basic // blocks. We try to access the value that is assigned to `SubExpr` in the // corresponding environment. -const Environment *SubExprEnv = StmtToEnv.getEnvironment(SubExpr); -if (!SubExprEnv) - return nullptr; - -if (auto *Val = -dyn_cast_or_null(SubExprEnv->getValueStrict(SubExpr))) - return Val; - -if (Env.getValueStrict(SubExpr) == nullptr) { - // Sub-expressions that are logic operators are not added in basic blocks - // (e.g. see CFG for `bool d = a && (b || c);`). If `SubExpr` is a logic - // operator, it may not have been evaluated and assigned a value yet. In - // that case, we need to first visit `SubExpr` and then try to get the - // value that gets assigned to it. +if (const Environment *SubExprEnv = StmtToEnv.getEnvironment(SubExpr)) + if (auto *Val = + dyn_cast_or_null(SubExprEnv->getValueStrict(SubExpr))) +return *Val; + +// The sub-expression may lie within a basic block that isn't reachable, +// even if we need it to evaluate the current (reachable) expression +// (see https://discourse.llvm.org/t/70775). In this case, visit `SubExpr` +// within the current environment and then try to get the value that gets +// assigned to it. +if (Env.getValueStrict(SubExpr) == nullptr) Visit(&SubExpr); -} - if (auto *Val = dyn_cast_or_null(Env.getValueStrict(SubExpr))) - return Val; + return *Val; // If the value of `SubExpr` is still unknown, we create a fresh symbolic // boolean value for it. -return &Env.makeAtomicBoolValue(); +return Env.makeAtomicBoolValue(); } // If context sensitivity is enabled, try to analyze the body of the callee diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index 726f2b7bbdcc..1a2442f0b12d 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -5140,6 +5140,26 @@ TEST(TransferTest, UnnamedBitfieldInitializer) { }); } +// Repro for a crash that used to occur with chained short-circuiting logical +//
[clang] 5ddb623 - [clang][dataflow] Remove unnecessary `ASTContext` parameter from `ControlFlowContext::build` overload.
Author: Martin Braenne Date: 2023-05-30T07:05:35Z New Revision: 5ddb623952cacba0a3933dacd4c70439ca95c70d URL: https://github.com/llvm/llvm-project/commit/5ddb623952cacba0a3933dacd4c70439ca95c70d DIFF: https://github.com/llvm/llvm-project/commit/5ddb623952cacba0a3933dacd4c70439ca95c70d.diff LOG: [clang][dataflow] Remove unnecessary `ASTContext` parameter from `ControlFlowContext::build` overload. When introducing this new overload in https://reviews.llvm.org/D151183, I didn't consider that the `ASTContext` parameter was unnecessary because it could also be obtained from the `FunctionDecl`. Reviewed By: gribozavr2, xazax.hun Differential Revision: https://reviews.llvm.org/D151549 Added: Modified: clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp clang/unittests/Analysis/FlowSensitive/TestingSupport.h clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h b/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h index f327011766069..bb36ed237c1e3 100644 --- a/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h +++ b/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h @@ -33,8 +33,7 @@ class ControlFlowContext { public: /// Builds a ControlFlowContext from a `FunctionDecl`. /// `Func.hasBody()` must be true, and `Func.isTemplated()` must be false. - static llvm::Expected build(const FunctionDecl &Func, - ASTContext &C); + static llvm::Expected build(const FunctionDecl &Func); /// Builds a ControlFlowContext from an AST node. `D` is the function in which /// `S` resides. `D.isTemplated()` must be false. diff --git a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp index c62bff33524cf..c80525dc4f34f 100644 --- a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp +++ b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp @@ -68,13 +68,13 @@ static llvm::BitVector findReachableBlocks(const CFG &Cfg) { } llvm::Expected -ControlFlowContext::build(const FunctionDecl &Func, ASTContext &C) { +ControlFlowContext::build(const FunctionDecl &Func) { if (!Func.hasBody()) return llvm::createStringError( std::make_error_code(std::errc::invalid_argument), "Cannot analyze function without a body"); - return build(Func, *Func.getBody(), C); + return build(Func, *Func.getBody(), Func.getASTContext()); } llvm::Expected diff --git a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp index 32612397ec024..27ec15adc5350 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp @@ -211,7 +211,7 @@ DataflowAnalysisContext::getControlFlowContext(const FunctionDecl *F) { return &It->second; if (F->hasBody()) { -auto CFCtx = ControlFlowContext::build(*F, F->getASTContext()); +auto CFCtx = ControlFlowContext::build(*F); // FIXME: Handle errors. assert(CFCtx); auto Result = FunctionContexts.insert({F, std::move(*CFCtx)}); diff --git a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h index d5591bee12dc2..aa2b2a241b224 100644 --- a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h +++ b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h @@ -241,7 +241,7 @@ checkDataflow(AnalysisInputs AI, llvm::errc::invalid_argument, "Could not find the target function."); // Build the control flow graph for the target function. -auto MaybeCFCtx = ControlFlowContext::build(*Target, Context); +auto MaybeCFCtx = ControlFlowContext::build(*Target); if (!MaybeCFCtx) return MaybeCFCtx.takeError(); auto &CFCtx = *MaybeCFCtx; diff --git a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp index 1d94b69cfce81..473750ad7a6cb 100644 --- a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp @@ -65,7 +65,7 @@ runAnalysis(llvm::StringRef Code, AnalysisT (*MakeAnalysis)(ASTContext &)) { assert(Func != nullptr); auto CFCtx = - llvm::cantFail(ControlFlowContext::build(*Func, AST->getASTContext())); + llvm::cantFail(ControlFlowContext::build(*Func)); AnalysisT Analysis = MakeAnalysis(AST->getASTContext()); DataflowAnalysisContext DACtx(std::make_unique()); ___
[clang] bfbe137 - [clang][dataflow] Eliminate intermediate `ReferenceValue`s from `Environment::DeclToLoc`.
Author: Martin Braenne Date: 2023-05-04T20:57:30Z New Revision: bfbe137888151dfd506df6b3319d08c4de0e00f5 URL: https://github.com/llvm/llvm-project/commit/bfbe137888151dfd506df6b3319d08c4de0e00f5 DIFF: https://github.com/llvm/llvm-project/commit/bfbe137888151dfd506df6b3319d08c4de0e00f5.diff LOG: [clang][dataflow] Eliminate intermediate `ReferenceValue`s from `Environment::DeclToLoc`. For the wider context of this change, see the RFC at https://discourse.llvm.org/t/70086. After this change, global and local variables of reference type are associated directly with the `StorageLocation` of the referenced object instead of the `StorageLocation` of a `ReferenceValue`. Some tests that explicitly check for an existence of `ReferenceValue` for a variable of reference type have been modified accordingly. As discussed in the RFC, I have added an assertion to `Environment::join()` to check that if both environments contain an entry for the same declaration in `DeclToLoc`, they both map to the same `StorageLocation`. As discussed in https://discourse.llvm.org/t/70086/5, this also necessitates removing declarations from `DeclToLoc` when they go out of scope. In the RFC, I proposed a gradual migration for this change, but it appears that all of the callers of `Environment::setStorageLocation(const ValueDecl &, SkipPast` are in the dataflow framework itself, and that there are only a few of them. As this is the function whose semantics are changing in a way that callers potentially need to adapt to, I've decided to change the semantics of the function directly. The semantics of `getStorageLocation(const ValueDecl &, SkipPast SP` now no longer depend on the behavior of the `SP` parameter. (There don't appear to be any callers that use `SkipPast::ReferenceThenPointer`, so I've added an assertion that forbids this usage.) This patch adds a default argument for the `SP` parameter and removes the explicit `SP` argument at the callsites that are touched by this change. A followup patch will remove the argument from the remaining callsites, allowing the `SkipPast` parameter to be removed entirely. (I don't want to do that in this patch so that semantics-changing changes can be reviewed separately from semantics-neutral changes.) Reviewed By: ymandel, xazax.hun, gribozavr2 Differential Revision: https://reviews.llvm.org/D149144 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index 9c027ef4552ee..cd1703be0507b 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -269,13 +269,24 @@ class Environment { /// /// Requirements: /// - /// `D` must not be assigned a storage location in the environment. + /// `D` must not already have a storage location in the environment. + /// + /// If `D` has reference type, `Loc` must refer directly to the referenced + /// object (if any), not to a `ReferenceValue`, and it is not permitted to + /// later change `Loc` to refer to a `ReferenceValue.` void setStorageLocation(const ValueDecl &D, StorageLocation &Loc); - /// Returns the storage location assigned to `D` in the environment, applying - /// the `SP` policy for skipping past indirections, or null if `D` isn't - /// assigned a storage location in the environment. - StorageLocation *getStorageLocation(const ValueDecl &D, SkipPast SP) const; + /// Returns the storage location assigned to `D` in the environment, or null + /// if `D` isn't assigned a storage location in the environment. + /// + /// Note that if `D` has reference type, the storage location that is returned + /// refers directly to the referenced object, not a `ReferenceValue`. + /// + /// The `SP` parameter is deprecated and has no effect. In addition, it is + /// not permitted to pass `SkipPast::ReferenceThenPointer` for this parameter. + /// New uses of this function should use the default argument for `SP`. + StorageLocation *getStorageLocation(const ValueDecl &D, + SkipPast SP = SkipPast::None) const; /// Assigns `Loc` as the storage location of `E` in the environment. /// @@ -320,7 +331,11 @@ class Environment { /// Equivalent to `getValue(getStorageLocation(D, SP), SkipPast::None)` if `D` /// is assigned a storage location in the environment, otherwise returns null. - Value *getValue(const ValueDecl &D, SkipPast SP) const; + /// + /// The `SP` par
cfe-commits@lists.llvm.org
Author: Martin Braenne Date: 2023-05-08T07:10:44Z New Revision: 9940fac7539597c08f03381527011e1280cd7489 URL: https://github.com/llvm/llvm-project/commit/9940fac7539597c08f03381527011e1280cd7489 DIFF: https://github.com/llvm/llvm-project/commit/9940fac7539597c08f03381527011e1280cd7489.diff LOG: [clang][dataflow][NFC] Remove `SkipPast` parameter from `getStorageLocation(const ValueDecl &). This parameter was already a no-op, so removing it doesn't change behavior. Depends On D149144 Reviewed By: ymandel, xazax.hun, gribozavr2 Differential Revision: https://reviews.llvm.org/D149151 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp clang/unittests/Analysis/FlowSensitive/SignAnalysisTest.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index cd1703be0507b..58b1d8b172b3d 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -281,12 +281,7 @@ class Environment { /// /// Note that if `D` has reference type, the storage location that is returned /// refers directly to the referenced object, not a `ReferenceValue`. - /// - /// The `SP` parameter is deprecated and has no effect. In addition, it is - /// not permitted to pass `SkipPast::ReferenceThenPointer` for this parameter. - /// New uses of this function should use the default argument for `SP`. - StorageLocation *getStorageLocation(const ValueDecl &D, - SkipPast SP = SkipPast::None) const; + StorageLocation *getStorageLocation(const ValueDecl &D) const; /// Assigns `Loc` as the storage location of `E` in the environment. /// diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index a4d3768b8b189..479aa12d191ee 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -245,7 +245,7 @@ void Environment::initFieldsGlobalsAndFuncs(const FunctionDecl *FuncDecl) { DACtx->addModeledFields(Fields); for (const VarDecl *D : Vars) { -if (getStorageLocation(*D, SkipPast::None) != nullptr) +if (getStorageLocation(*D) != nullptr) continue; auto &Loc = createStorageLocation(D->getType().getNonReferenceType()); setStorageLocation(*D, Loc); @@ -254,7 +254,7 @@ void Environment::initFieldsGlobalsAndFuncs(const FunctionDecl *FuncDecl) { } for (const FunctionDecl *FD : Funcs) { -if (getStorageLocation(*FD, SkipPast::None) != nullptr) +if (getStorageLocation(*FD) != nullptr) continue; auto &Loc = createStorageLocation(FD->getType()); setStorageLocation(*FD, Loc); @@ -605,10 +605,7 @@ void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) { DeclToLoc[&D] = &Loc; } -StorageLocation *Environment::getStorageLocation(const ValueDecl &D, - SkipPast SP) const { - assert(SP != SkipPast::ReferenceThenPointer); - +StorageLocation *Environment::getStorageLocation(const ValueDecl &D) const { auto It = DeclToLoc.find(&D); if (It == DeclToLoc.end()) return nullptr; @@ -686,7 +683,7 @@ Value *Environment::getValue(const StorageLocation &Loc) const { Value *Environment::getValue(const ValueDecl &D, SkipPast SP) const { assert(SP != SkipPast::ReferenceThenPointer); - auto *Loc = getStorageLocation(D, SP); + auto *Loc = getStorageLocation(D); if (Loc == nullptr) return nullptr; return getValue(*Loc); diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp index ddabf352fd111..50eb7e9011bda 100644 --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -219,7 +219,7 @@ class TransferVisitor : public ConstStmtVisitor { void VisitDeclRefExpr(const DeclRefExpr *S) { const ValueDecl *VD = S->getDecl(); assert(VD != nullptr); -auto *DeclLoc = Env.getStorageLocation(*VD, SkipPast::None); +auto *DeclLoc = Env.getStorageLocation(*VD); if (DeclLoc == nullptr) return; @@ -533,7 +533,7 @@ class TransferVisitor : public ConstStmtVisitor { if (auto *D = dyn_cast(Member)) { if (D->hasGlobalStorage()) { -auto *VarDeclLoc = Env.getStorageLocation(*D, SkipPast::None); +auto *VarDeclLoc = Env.
cfe-commits@lists.llvm.org
Author: Martin Braenne Date: 2023-05-09T07:42:20Z New Revision: 0c852dc88e9276b74532fd7d233dd23ec1bbed6f URL: https://github.com/llvm/llvm-project/commit/0c852dc88e9276b74532fd7d233dd23ec1bbed6f DIFF: https://github.com/llvm/llvm-project/commit/0c852dc88e9276b74532fd7d233dd23ec1bbed6f.diff LOG: [clang][dataflow][NFC] Remove `SkipPast` param from `getValue(const ValueDecl &)`. This parameter was already a no-op, so removing it doesn't change behavior. Reviewed By: ymandel Differential Revision: https://reviews.llvm.org/D150137 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp clang/unittests/Analysis/FlowSensitive/ChromiumCheckModelTest.cpp clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp clang/unittests/Analysis/FlowSensitive/SignAnalysisTest.cpp clang/unittests/Analysis/FlowSensitive/TestingSupport.h clang/unittests/Analysis/FlowSensitive/TransferTest.cpp clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index 7f24755d9923a..c23e0db7f82d3 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -314,11 +314,7 @@ class Environment { /// Equivalent to `getValue(getStorageLocation(D, SP), SkipPast::None)` if `D` /// is assigned a storage location in the environment, otherwise returns null. - /// - /// The `SP` parameter is deprecated and has no effect. In addition, it is - /// not permitted to pass `SkipPast::ReferenceThenPointer` for this parameter. - /// New uses of this function should use the default argument for `SP`. - Value *getValue(const ValueDecl &D, SkipPast SP = SkipPast::None) const; + Value *getValue(const ValueDecl &D) const; /// Equivalent to `getValue(getStorageLocation(E, SP), SkipPast::None)` if `E` /// is assigned a storage location in the environment, otherwise returns null. diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index 479aa12d191ee..0d269f503f4eb 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -680,9 +680,7 @@ Value *Environment::getValue(const StorageLocation &Loc) const { return It == LocToVal.end() ? nullptr : It->second; } -Value *Environment::getValue(const ValueDecl &D, SkipPast SP) const { - assert(SP != SkipPast::ReferenceThenPointer); - +Value *Environment::getValue(const ValueDecl &D) const { auto *Loc = getStorageLocation(D); if (Loc == nullptr) return nullptr; diff --git a/clang/unittests/Analysis/FlowSensitive/ChromiumCheckModelTest.cpp b/clang/unittests/Analysis/FlowSensitive/ChromiumCheckModelTest.cpp index 86feca486ec7c..f88a179f93a45 100644 --- a/clang/unittests/Analysis/FlowSensitive/ChromiumCheckModelTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/ChromiumCheckModelTest.cpp @@ -158,7 +158,7 @@ TEST(ChromiumCheckModelTest, CheckSuccessImpliesConditionHolds) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); -auto *FooVal = cast(Env.getValue(*FooDecl, SkipPast::None)); +auto *FooVal = cast(Env.getValue(*FooDecl)); EXPECT_TRUE(Env.flowConditionImplies(*FooVal)); }; @@ -189,7 +189,7 @@ TEST(ChromiumCheckModelTest, UnrelatedCheckIgnored) { const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); ASSERT_THAT(FooDecl, NotNull()); -auto *FooVal = cast(Env.getValue(*FooDecl, SkipPast::None)); +auto *FooVal = cast(Env.getValue(*FooDecl)); EXPECT_FALSE(Env.flowConditionImplies(*FooVal)); }; diff --git a/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp b/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp index 2f874b44c49bf..1c78dd380c774 100644 --- a/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp @@ -124,7 +124,7 @@ TEST_F(EnvironmentTest, InitGlobalVarsFun) { // Verify the global variable is populated when we analyze `Target`. Environment Env(DAContext, *Fun); - EXPECT_THAT(Env.getValue(*Var, SkipPast::None), NotNull()); + EXPECT_THAT(Env.getValue(*Var), NotNull()); } // Tests that fields mentioned only in default member initializers are included @@ -255,7 +255,7 @@ TEST_F(EnvironmentTest, InitGlobalVarsConstructor) { // Verify the global variable is populated when we analyze `Target`. Environment Env(DAContext, *Ctor); - EXPECT_THAT(En
[clang] 48bc715 - [clang][dataflow] Eliminate `SkipPast::ReferenceThenPointer`.
Author: Martin Braenne Date: 2023-05-15T04:33:29Z New Revision: 48bc71505e03694caac6afb2431ff1157a2382a8 URL: https://github.com/llvm/llvm-project/commit/48bc71505e03694caac6afb2431ff1157a2382a8 DIFF: https://github.com/llvm/llvm-project/commit/48bc71505e03694caac6afb2431ff1157a2382a8.diff LOG: [clang][dataflow] Eliminate `SkipPast::ReferenceThenPointer`. As a replacement, we provide the accessors `getImplicitObjectLocation()` and `getBaseObjectLocation()`, which are higher-level constructs that cover the use cases in which `SkipPast::ReferenceThenPointer` was typically used. Unfortunately, it isn't possible to use these accessors in UncheckedOptionalAccessModel.cpp; I've added a FIXME to the code explaining the details. I initially attempted to resolve the issue as part of this patch, but it turned out to be non-trivial to fix. Instead, I have therefore added a lower-level replacement for `SkipPast::ReferenceThenPointer` that is used only within this file. The wider context of this change is that `SkipPast` will be going away entirely. See also the RFC at https://discourse.llvm.org/t/70086. Reviewed By: ymandel, gribozavr2 Differential Revision: https://reviews.llvm.org/D149838 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index c23e0db7f82d3..d734ae5c66fe8 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -46,9 +46,6 @@ enum class SkipPast { None, /// An optional reference should be skipped past. Reference, - /// An optional reference should be skipped past, then an optional pointer - /// should be skipped past. - ReferenceThenPointer, }; /// Indicates the result of a tentative comparison. @@ -477,6 +474,19 @@ class Environment { AtomicBoolValue *FlowConditionToken; }; +/// Returns the storage location for the implicit object of a +/// `CXXMemberCallExpr`, or null if none is defined in the environment. +/// Dereferences the pointer if the member call expression was written using +/// `->`. +AggregateStorageLocation * +getImplicitObjectLocation(const CXXMemberCallExpr &MCE, const Environment &Env); + +/// Returns the storage location for the base object of a `MemberExpr`, or null +/// if none is defined in the environment. Dereferences the pointer if the +/// member expression was written using `->`. +AggregateStorageLocation *getBaseObjectLocation(const MemberExpr &ME, +const Environment &Env); + } // namespace dataflow } // namespace clang diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index 0d269f503f4eb..7b1944f273cf0 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -782,11 +782,6 @@ StorageLocation &Environment::skip(StorageLocation &Loc, SkipPast SP) const { if (auto *Val = dyn_cast_or_null(getValue(Loc))) return Val->getReferentLoc(); return Loc; - case SkipPast::ReferenceThenPointer: -StorageLocation &LocPastRef = skip(Loc, SkipPast::Reference); -if (auto *Val = dyn_cast_or_null(getValue(LocPastRef))) - return Val->getPointeeLoc(); -return LocPastRef; } llvm_unreachable("bad SkipPast kind"); } @@ -828,5 +823,39 @@ void Environment::dump() const { dump(llvm::dbgs()); } +AggregateStorageLocation * +getImplicitObjectLocation(const CXXMemberCallExpr &MCE, + const Environment &Env) { + Expr *ImplicitObject = MCE.getImplicitObjectArgument(); + if (ImplicitObject == nullptr) +return nullptr; + StorageLocation *Loc = + Env.getStorageLocation(*ImplicitObject, SkipPast::Reference); + if (Loc == nullptr) +return nullptr; + if (ImplicitObject->getType()->isPointerType()) { +if (auto *Val = cast_or_null(Env.getValue(*Loc))) + return &cast(Val->getPointeeLoc()); +return nullptr; + } + return cast(Loc); +} + +AggregateStorageLocation *getBaseObjectLocation(const MemberExpr &ME, +const Environment &Env) { + Expr *Base = ME.getBase(); + if (Base == nullptr) +return nullptr; + StorageLocation *Loc = Env.getStorageLocation(*Base, SkipPast::Reference); + if (Loc == nullptr) +return nullptr; + if (ME.isArrow()) { +if (auto *Val = cast_or_null(Env.
[clang] 1a42f79 - [clang][dataflow] Don't analyze templated declarations.
Author: Martin Braenne Date: 2023-05-15T11:04:51Z New Revision: 1a42f795587b9d57291d009989aace6efd0a7a7f URL: https://github.com/llvm/llvm-project/commit/1a42f795587b9d57291d009989aace6efd0a7a7f DIFF: https://github.com/llvm/llvm-project/commit/1a42f795587b9d57291d009989aace6efd0a7a7f.diff LOG: [clang][dataflow] Don't analyze templated declarations. Attempting to analyze templated code doesn't have a good cost-benefit ratio. We have so far done a best-effort attempt at this, but maintaining this support has an ongoing high maintenance cost because the AST for templates can violate a lot of the invariants that otherwise hold for the AST of concrete code. As just one example, in concrete code the operand of a UnaryOperator '*' is always a prvalue (https://godbolt.org/z/s3e5xxMd1), but in templates this isn't true (https://godbolt.org/z/6W9xxGvoM). Further rationale for not analyzing templates: * The semantics of a template itself are weakly defined; semantics can depend strongly on the concrete template arguments. Analyzing the template itself (as opposed to an instantiation) therefore has limited value. * Analyzing templates requires a lot of special-case code that isn't necessary for concrete code because dependent types are hard to deal with and the AST violates invariants that otherwise hold for concrete code (see above). * There's precedent in that neither Clang Static Analyzer nor the flow-sensitive warnings in Clang (such as uninitialized variables) support analyzing templates. Reviewed By: gribozavr2, xazax.hun Differential Revision: https://reviews.llvm.org/D150352 Added: Modified: clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/unittests/Analysis/FlowSensitive/TestingSupport.h clang/unittests/Analysis/FlowSensitive/TransferTest.cpp clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h b/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h index 3495bdfc538cb..b51e2cb23634d 100644 --- a/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h +++ b/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h @@ -32,7 +32,13 @@ namespace dataflow { class ControlFlowContext { public: /// Builds a ControlFlowContext from an AST node. `D` is the function in which - /// `S` resides and must not be null. + /// `S` resides. `D.isTemplated()` must be false. + static llvm::Expected build(const Decl &D, Stmt &S, + ASTContext &C); + + /// Builds a ControlFlowContext from an AST node. `D` is the function in which + /// `S` resides. `D` must not be null and `D->isTemplated()` must be false. + LLVM_DEPRECATED("Use the version that takes a const Decl & instead", "") static llvm::Expected build(const Decl *D, Stmt &S, ASTContext &C); diff --git a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp index 5520633da68ae..4556787d10a8e 100644 --- a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp +++ b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp @@ -68,7 +68,12 @@ static llvm::BitVector findReachableBlocks(const CFG &Cfg) { } llvm::Expected -ControlFlowContext::build(const Decl *D, Stmt &S, ASTContext &C) { +ControlFlowContext::build(const Decl &D, Stmt &S, ASTContext &C) { + if (D.isTemplated()) +return llvm::createStringError( +std::make_error_code(std::errc::invalid_argument), +"Cannot analyze templated declarations"); + CFG::BuildOptions Options; Options.PruneTriviallyFalseEdges = true; Options.AddImplicitDtors = true; @@ -79,7 +84,7 @@ ControlFlowContext::build(const Decl *D, Stmt &S, ASTContext &C) { // Ensure that all sub-expressions in basic blocks are evaluated. Options.setAllAlwaysAdd(); - auto Cfg = CFG::buildCFG(D, &S, &C, Options); + auto Cfg = CFG::buildCFG(&D, &S, &C, Options); if (Cfg == nullptr) return llvm::createStringError( std::make_error_code(std::errc::invalid_argument), @@ -90,9 +95,19 @@ ControlFlowContext::build(const Decl *D, Stmt &S, ASTContext &C) { llvm::BitVector BlockReachable = findReachableBlocks(*Cfg); - return ControlFlowContext(D, std::move(Cfg), std::move(StmtToBlock), + return ControlFlowContext(&D, std::move(Cfg), std::move(StmtToBlock), std::move(BlockReachable)); } +llvm::Expected +ControlFlowContext::build(const Decl *D, Stmt &S, ASTContext &C) { + if (D == nullptr) +return llvm::createStringError( +std::mak
[clang] 080ee85 - [clang][dataflow] Add `Strict` versions of `Value` and `StorageLocation` accessors.
Author: Martin Braenne Date: 2023-05-17T09:30:47Z New Revision: 080ee850c639be96b8bea8008088f2b036ff0f15 URL: https://github.com/llvm/llvm-project/commit/080ee850c639be96b8bea8008088f2b036ff0f15 DIFF: https://github.com/llvm/llvm-project/commit/080ee850c639be96b8bea8008088f2b036ff0f15.diff LOG: [clang][dataflow] Add `Strict` versions of `Value` and `StorageLocation` accessors. This is part of the gradual migration to strict handling of value categories, as described in the RFC at https://discourse.llvm.org/t/70086. This patch migrates some representative calls of the newly deprecated accessors to the new `Strict` functions. Followup patches will migrate the remaining callers. (There are a large number of callers, with some subtlety involved in some of them, so it makes sense to split this up into multiple patches rather than migrating all callers in one go.) The `Strict` accessors as implemented here have some differences in semantics compared to the semantics originally proposed in the RFC; specifically: * `setStorageLocationStrict()`: The RFC proposes to create an intermediate `ReferenceValue` that then refers to the `StorageLocation` for the glvalue. It turns out though that, even today, most places in the code are not doing this but are instead associating glvalues directly with their `StorageLocation`. It therefore didn't seem to make sense to introduce new `ReferenceValue`s where there were none previously, so I have chosen to instead make `setStorageLocationStrict()` simply call through to `setStorageLocation(const Expr &, StorageLocation &)` and merely add the assertion that the expression must be a glvalue. * `getStorageLocationStrict()`: The RFC proposes that this should assert that the storage location for the glvalue expression is associated with an intermediate `ReferenceValue`, but, as explained, this is often not true. The current state is inconsistent: Sometimes the intermediate `ReferenceValue` is there, sometimes it isn't. For this reason, `getStorageLocationStrict()` skips past a `ReferenceValue` if it is there but otherwise directly returns the storage location associated with the expression. This behavior is equivalent to the existing behavior of `SkipPast::Reference`. * `setValueStrict()`: The RFC proposes that this should always create the same `StorageLocation` for a given `Value`, but, in fact, the transfer functions that exist today don't guarantee this; almost all transfer functions unconditionally create a new `StorageLocation` when associating an expression with a `Value`. There appears to be one special case: `TerminatorVisitor::extendFlowCondition()` checks whether the expression is already associated with a `StorageLocation` and, if so, reuses the existing `StorageLocation` instead of creating a new one. For this reason, `setValueStrict()` implements this logic (preserve an existing `StorageLocation`) but makes no attempt to always associate the same `StorageLocation` with a given `Value`, as nothing in the framework appers to require this. As `TerminatorVisitor::extendFlowCondition()` is an interesting special case, the `setValue()` call there is among the ones that this patch migrates to `setValueStrict()`. Reviewed By: sammccall, ymandel, xazax.hun Differential Revision: https://reviews.llvm.org/D150653 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index d734ae5c66fe8..6f2f7f4004f84 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -270,16 +270,54 @@ class Environment { /// Assigns `Loc` as the storage location of `E` in the environment. /// + /// This function is deprecated; prefer `setStorageLocationStrict()`. + /// For details, see https://discourse.llvm.org/t/70086. + /// /// Requirements: /// /// `E` must not be assigned a storage location in the environment. void setStorageLocation(const Expr &E, StorageLocation &Loc); + /// Assigns `Loc` as the storage location of the glvalue `E` in the + /// environment. + /// + /// This function is the preferred alternative to + /// `setStorageLocation(const Expr &, StorageLocation &)`. Once the migration + /// to strict handling of value categories is complete (see + /// https://discourse.llvm.org/t/70086), `setStorageLocation()` will be + /// removed and this function will be renamed to `setStorageLocation()`. +
[clang] 6a81e69 - [clang][dataflow] Remove unused parameter from `diagnoseUnwrapCall()`.
Author: Martin Braenne Date: 2023-05-17T14:27:58Z New Revision: 6a81e694ab806d257e43cbc2e32c06099d70cbd8 URL: https://github.com/llvm/llvm-project/commit/6a81e694ab806d257e43cbc2e32c06099d70cbd8 DIFF: https://github.com/llvm/llvm-project/commit/6a81e694ab806d257e43cbc2e32c06099d70cbd8.diff LOG: [clang][dataflow] Remove unused parameter from `diagnoseUnwrapCall()`. Reviewed By: sammccall Differential Revision: https://reviews.llvm.org/D150756 Added: Modified: clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp index 680c4d11a23b7..24a3682f438cb 100644 --- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp +++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp @@ -864,8 +864,7 @@ auto buildTransferMatchSwitch() { .Build(); } -std::vector diagnoseUnwrapCall(const Expr *UnwrapExpr, - const Expr *ObjectExpr, +std::vector diagnoseUnwrapCall(const Expr *ObjectExpr, const Environment &Env) { if (auto *OptionalVal = getValueBehindPossiblePointer(*ObjectExpr, Env)) { auto *Prop = OptionalVal->getProperty("has_value"); @@ -893,16 +892,16 @@ auto buildDiagnoseMatchSwitch( valueCall(IgnorableOptional), [](const CXXMemberCallExpr *E, const MatchFinder::MatchResult &, const Environment &Env) { -return diagnoseUnwrapCall(E, E->getImplicitObjectArgument(), Env); +return diagnoseUnwrapCall(E->getImplicitObjectArgument(), Env); }) // optional::operator*, optional::operator-> - .CaseOfCFGStmt( - valueOperatorCall(IgnorableOptional), - [](const CallExpr *E, const MatchFinder::MatchResult &, - const Environment &Env) { -return diagnoseUnwrapCall(E, E->getArg(0), Env); - }) + .CaseOfCFGStmt(valueOperatorCall(IgnorableOptional), + [](const CallExpr *E, + const MatchFinder::MatchResult &, + const Environment &Env) { + return diagnoseUnwrapCall(E->getArg(0), Env); + }) .Build(); } ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 6ab900f - [clang][dataflow] Add support for new expressions.
Author: Martin Braenne Date: 2023-04-18T04:11:43Z New Revision: 6ab900f8746e7d8e24afafb5886a40801f6799f4 URL: https://github.com/llvm/llvm-project/commit/6ab900f8746e7d8e24afafb5886a40801f6799f4 DIFF: https://github.com/llvm/llvm-project/commit/6ab900f8746e7d8e24afafb5886a40801f6799f4.diff LOG: [clang][dataflow] Add support for new expressions. Reviewed By: xazax.hun, gribozavr2 Differential Revision: https://reviews.llvm.org/D147698 Added: Modified: clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp index aa8fe907b167..1d273e77ef0b 100644 --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -469,6 +469,20 @@ class TransferVisitor : public ConstStmtVisitor { Env.setValue(Loc, Env.create(*ThisPointeeLoc)); } + void VisitCXXNewExpr(const CXXNewExpr *S) { +auto &Loc = Env.createStorageLocation(*S); +Env.setStorageLocation(*S, Loc); +if (Value *Val = Env.createValue(S->getType())) + Env.setValue(Loc, *Val); + } + + void VisitCXXDeleteExpr(const CXXDeleteExpr *S) { +// Empty method. +// We consciously don't do anything on deletes. Diagnosing double deletes +// (for example) should be done by a specific analysis, not by the +// framework. + } + void VisitReturnStmt(const ReturnStmt *S) { if (!Env.getAnalysisOptions().ContextSensitiveOpts) return; diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index 1bb772a93bda..8f02161834dc 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -5170,4 +5170,66 @@ TEST(TransferTest, NoReturnFunctionInsideShortCircuitedBooleanOp) { }); } +TEST(TransferTest, NewExpressions) { + std::string Code = R"( +void target() { + int *p = new int(42); + // [[after_new]] +} + )"; + runDataflow( + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) { +const Environment &Env = +getEnvironmentAtAnnotation(Results, "after_new"); + +auto &P = getValueForDecl(ASTCtx, Env, "p"); + +EXPECT_THAT(Env.getValue(P.getPointeeLoc()), NotNull()); + }); +} + +TEST(TransferTest, NewExpressions_Structs) { + std::string Code = R"( +struct Inner { + int InnerField; +}; + +struct Outer { + Inner OuterField; +}; + +void target() { + Outer *p = new Outer; + // Access the fields to make sure the analysis actually generates children + // for them in the `AggregateStorageLoc` and `StructValue`. + p->OuterField.InnerField; + // [[after_new]] +} + )"; + runDataflow( + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) { +const Environment &Env = +getEnvironmentAtAnnotation(Results, "after_new"); + +const ValueDecl *OuterField = findValueDecl(ASTCtx, "OuterField"); +const ValueDecl *InnerField = findValueDecl(ASTCtx, "InnerField"); + +auto &P = getValueForDecl(ASTCtx, Env, "p"); + +auto &OuterLoc = cast(P.getPointeeLoc()); +auto &OuterFieldLoc = +cast(OuterLoc.getChild(*OuterField)); +auto &InnerFieldLoc = OuterFieldLoc.getChild(*InnerField); + +// Values for the struct and all fields exist after the new. +EXPECT_THAT(Env.getValue(OuterLoc), NotNull()); +EXPECT_THAT(Env.getValue(OuterFieldLoc), NotNull()); +EXPECT_THAT(Env.getValue(InnerFieldLoc), NotNull()); + }); +} + } // namespace ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] d9e7173 - [clang][dataflow] Associate `FunctionToPointerDecay` nodes with a value.
Author: Martin Braenne Date: 2023-04-18T07:15:29Z New Revision: d9e717338f8042664177250315364094262c7073 URL: https://github.com/llvm/llvm-project/commit/d9e717338f8042664177250315364094262c7073 DIFF: https://github.com/llvm/llvm-project/commit/d9e717338f8042664177250315364094262c7073.diff LOG: [clang][dataflow] Associate `FunctionToPointerDecay` nodes with a value. To ensure that we have a pointee for the `PointerValue`, we also create storage locations for `FunctionDecl`s referenced in the function under analysis. Reviewed By: gribozavr2 Differential Revision: https://reviews.llvm.org/D148006 Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index 97ea6a573cffd..4e65d974133a6 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -492,9 +492,9 @@ class Environment { void pushCallInternal(const FunctionDecl *FuncDecl, ArrayRef Args); - /// Assigns storage locations and values to all global variables and fields - /// referenced in `FuncDecl`. `FuncDecl` must have a body. - void initFieldsAndGlobals(const FunctionDecl *FuncDecl); + /// Assigns storage locations and values to all global variables, fields + /// and functions referenced in `FuncDecl`. `FuncDecl` must have a body. + void initFieldsGlobalsAndFuncs(const FunctionDecl *FuncDecl); // `DACtx` is not null and not owned by this object. DataflowAnalysisContext *DACtx; diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index 680036b6a5b39..9f5b3adc8b1b1 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -162,10 +162,19 @@ static void insertIfGlobal(const Decl &D, Vars.insert(V); } -static void getFieldsAndGlobalVars(const Decl &D, - llvm::DenseSet &Fields, - llvm::DenseSet &Vars) { +static void insertIfFunction(const Decl &D, + llvm::DenseSet &Funcs) { + if (auto *FD = dyn_cast(&D)) +Funcs.insert(FD); +} + +static void +getFieldsGlobalsAndFuncs(const Decl &D, + llvm::DenseSet &Fields, + llvm::DenseSet &Vars, + llvm::DenseSet &Funcs) { insertIfGlobal(D, Vars); + insertIfFunction(D, Funcs); if (const auto *Decomp = dyn_cast(&D)) for (const auto *B : Decomp->bindings()) if (auto *ME = dyn_cast_or_null(B->getBinding())) @@ -174,27 +183,32 @@ static void getFieldsAndGlobalVars(const Decl &D, Fields.insert(FD); } -/// Traverses `S` and inserts into `Vars` any global storage values that are -/// declared in or referenced from sub-statements. -static void getFieldsAndGlobalVars(const Stmt &S, - llvm::DenseSet &Fields, - llvm::DenseSet &Vars) { +/// Traverses `S` and inserts into `Fields`, `Vars` and `Funcs` any fields, +/// global variables and functions that are declared in or referenced from +/// sub-statements. +static void +getFieldsGlobalsAndFuncs(const Stmt &S, + llvm::DenseSet &Fields, + llvm::DenseSet &Vars, + llvm::DenseSet &Funcs) { for (auto *Child : S.children()) if (Child != nullptr) - getFieldsAndGlobalVars(*Child, Fields, Vars); + getFieldsGlobalsAndFuncs(*Child, Fields, Vars, Funcs); if (auto *DS = dyn_cast(&S)) { if (DS->isSingleDecl()) - getFieldsAndGlobalVars(*DS->getSingleDecl(), Fields, Vars); + getFieldsGlobalsAndFuncs(*DS->getSingleDecl(), Fields, Vars, Funcs); else for (auto *D : DS->getDeclGroup()) - getFieldsAndGlobalVars(*D, Fields, Vars); +getFieldsGlobalsAndFuncs(*D, Fields, Vars, Funcs); } else if (auto *E = dyn_cast(&S)) { insertIfGlobal(*E->getDecl(), Vars); +insertIfFunction(*E->getDecl(), Funcs); } else if (auto *E = dyn_cast(&S)) { // FIXME: should we be using `E->getFoundDecl()`? const ValueDecl *VD = E->getMemberDecl(); insertIfGlobal(*VD, Vars); +insertIfFunction(*VD, Funcs); if (const auto *FD = dyn_cast(VD)) Fields.insert(FD); } @@ -202,11 +216,12 @@ static void getFieldsAndGlobalVars(const Stmt &S, // FIXME: Add support for resetting globals after function calls to enable // the implementatio
[clang] 6b85cc1 - [clang][dataflow] Use existing accessors to check for copy and move assignment ops.
Author: Martin Braenne Date: 2023-04-24T14:32:09Z New Revision: 6b85cc18eb7be0fdc01b8586347750e65e56a4c3 URL: https://github.com/llvm/llvm-project/commit/6b85cc18eb7be0fdc01b8586347750e65e56a4c3 DIFF: https://github.com/llvm/llvm-project/commit/6b85cc18eb7be0fdc01b8586347750e65e56a4c3.diff LOG: [clang][dataflow] Use existing accessors to check for copy and move assignment ops. Reviewed By: gribozavr2 Differential Revision: https://reviews.llvm.org/D148612 Added: Modified: clang/lib/Analysis/FlowSensitive/Transfer.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp index 2d85e7b90f73..0814257d5cd3 100644 --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -646,9 +646,12 @@ class TransferVisitor : public ConstStmtVisitor { assert(Arg1 != nullptr); // Evaluate only copy and move assignment operators. - auto *Arg0Type = Arg0->getType()->getUnqualifiedDesugaredType(); - auto *Arg1Type = Arg1->getType()->getUnqualifiedDesugaredType(); - if (Arg0Type != Arg1Type) + const auto *Method = + dyn_cast_or_null(S->getDirectCallee()); + if (!Method) +return; + if (!Method->isCopyAssignmentOperator() && + !Method->isMoveAssignmentOperator()) return; auto *ObjectLoc = Env.getStorageLocation(*Arg0, SkipPast::Reference); ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 791b0fd - [clang][dataflow] Change PruneTriviallyFalseEdges for building CFG
Author: Kinuko Yasuda Date: 2023-05-03T18:42:15Z New Revision: 791b0fd02668fd0fcf07788d4e16bb468434f4bf URL: https://github.com/llvm/llvm-project/commit/791b0fd02668fd0fcf07788d4e16bb468434f4bf DIFF: https://github.com/llvm/llvm-project/commit/791b0fd02668fd0fcf07788d4e16bb468434f4bf.diff LOG: [clang][dataflow] Change PruneTriviallyFalseEdges for building CFG Keeping this false could end up with extra iterations on a lot of loops that aren't real ones (e.g. they could be a do-while-false for macros), and makes the analyses very slow. This patch changes the default for CFG::BuildOptions.PruneTriviallyFalseEdges to true to avoid it. Reviewed By: ymandel, xazax.hun, gribozavr2 Differential Revision: https://reviews.llvm.org/D149640 Added: Modified: clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp index 6699a0fc9d79e..5520633da68ae 100644 --- a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp +++ b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp @@ -70,7 +70,7 @@ static llvm::BitVector findReachableBlocks(const CFG &Cfg) { llvm::Expected ControlFlowContext::build(const Decl *D, Stmt &S, ASTContext &C) { CFG::BuildOptions Options; - Options.PruneTriviallyFalseEdges = false; + Options.PruneTriviallyFalseEdges = true; Options.AddImplicitDtors = true; Options.AddTemporaryDtors = true; Options.AddInitializers = true; diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index 750d095af451a..c8161c8f40fc9 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -2644,7 +2644,7 @@ TEST(TransferTest, VarDeclInDoWhile) { void target(int *Foo) { do { int Bar = *Foo; - } while (true); + } while (false); (void)0; /*[[p]]*/ } @@ -2675,6 +2675,24 @@ TEST(TransferTest, VarDeclInDoWhile) { }); } +TEST(TransferTest, UnreachableAfterWhileTrue) { + std::string Code = R"( +void target() { + while (true) {} + (void)0; + /*[[p]]*/ +} + )"; + runDataflow( + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) { +// The node after the while-true is pruned because it is trivially +// known to be unreachable. +ASSERT_TRUE(Results.empty()); + }); +} + TEST(TransferTest, AggregateInitialization) { std::string BracesCode = R"( struct A { ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] c8f81ee - [clang-tidy] bugprone-use-after-move: Ctor arguments should be sequenced if ctor call is written as list-initialization.
Author: Martin Braenne Date: 2023-05-04T12:05:39Z New Revision: c8f81ee1da325760a4bbd83c8c54ecc9645f8e20 URL: https://github.com/llvm/llvm-project/commit/c8f81ee1da325760a4bbd83c8c54ecc9645f8e20 DIFF: https://github.com/llvm/llvm-project/commit/c8f81ee1da325760a4bbd83c8c54ecc9645f8e20.diff LOG: [clang-tidy] bugprone-use-after-move: Ctor arguments should be sequenced if ctor call is written as list-initialization. See https://timsong-cpp.github.io/cppwp/n4868/dcl.init#list-4 This eliminates a false positive in bugprone-use-after-move; this newly added test used to be falsely classified as a use-after-move: ``` A a; S3 s3{a.getInt(), std::move(a)}; ``` Reviewed By: PiotrZSL Differential Revision: https://reviews.llvm.org/D148110 Added: Modified: clang-tools-extra/clang-tidy/utils/ExprSequence.cpp clang-tools-extra/docs/ReleaseNotes.rst clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp Removed: diff --git a/clang-tools-extra/clang-tidy/utils/ExprSequence.cpp b/clang-tools-extra/clang-tidy/utils/ExprSequence.cpp index f9555be57e738..50df451ecfa26 100644 --- a/clang-tools-extra/clang-tidy/utils/ExprSequence.cpp +++ b/clang-tools-extra/clang-tidy/utils/ExprSequence.cpp @@ -131,6 +131,16 @@ const Stmt *ExprSequence::getSequenceSuccessor(const Stmt *S) const { } } } +} else if (const auto *ConstructExpr = dyn_cast(Parent)) { + // Constructor arguments are sequenced if the constructor call is written + // as list-initialization. + if (ConstructExpr->isListInitialization()) { +for (unsigned I = 1; I < ConstructExpr->getNumArgs(); ++I) { + if (ConstructExpr->getArg(I - 1) == S) { +return ConstructExpr->getArg(I); + } +} + } } else if (const auto *Compound = dyn_cast(Parent)) { // Compound statement: Each sub-statement is sequenced after the // statements that precede it. diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index e4220b3134714..98f18cc539faf 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -229,8 +229,9 @@ Changes in existing checks to ``std::forward``. - Improved :doc:`bugprone-use-after-move - ` check to also cover constructor - initializers. + ` check. Detect uses and moves in + constructor initializers. Correctly handle constructor arguments as being + sequenced when constructor call is written as list-initialization. - Deprecated :doc:`cert-dcl21-cpp ` check. diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp index 1e0831048dbd4..00b1da1e727e4 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp @@ -1160,42 +1160,63 @@ void commaOperatorSequences() { } } +namespace InitializerListSequences { + +struct S1 { + int i; + A a; +}; + +struct S2 { + A a; + int i; +}; + +struct S3 { + S3() {} + S3(int, A) {} + S3(A, int) {} +}; + // An initializer list sequences its initialization clauses. void initializerListSequences() { { -struct S1 { - int i; - A a; -}; -{ - A a; - S1 s1{a.getInt(), std::move(a)}; -} -{ - A a; - S1 s1{.i = a.getInt(), .a = std::move(a)}; -} +A a; +S1 s1{a.getInt(), std::move(a)}; } { -struct S2 { - A a; - int i; -}; -{ - A a; - S2 s2{std::move(a), a.getInt()}; - // CHECK-NOTES: [[@LINE-1]]:27: warning: 'a' used after it was moved - // CHECK-NOTES: [[@LINE-2]]:13: note: move occurred here -} -{ - A a; - S2 s2{.a = std::move(a), .i = a.getInt()}; - // CHECK-NOTES: [[@LINE-1]]:37: warning: 'a' used after it was moved - // CHECK-NOTES: [[@LINE-2]]:13: note: move occurred here -} +A a; +S1 s1{.i = a.getInt(), .a = std::move(a)}; + } + { +A a; +S2 s2{std::move(a), a.getInt()}; +// CHECK-NOTES: [[@LINE-1]]:25: warning: 'a' used after it was moved +// CHECK-NOTES: [[@LINE-2]]:11: note: move occurred here + } + { +A a; +S2 s2{.a = std::move(a), .i = a.getInt()}; +// CHECK-NOTES: [[@LINE-1]]:35: warning: 'a' used after it was moved +// CHECK-NOTES: [[@LINE-2]]:11: note: move occurred here + } + { +// Check the case where the constructed type has a constructor and the +// initializer list therefore manifests as a `CXXConstructExpr` instead of +// an `InitListExpr`. +A a; +S3 s3{a.getInt(), std::move(a)}; + } + { +A a; +S3 s3{std::move(a), a.getInt()}; +// CHECK-NOTES: [[@LINE-1]]:25: warning: 'a' used after it was moved +// CHECK-NOTES: [[@LINE-2]]:11: note: mov
[clang] c849843 - [clang][dataflow][NFC] Eliminate unnecessary helper `stripReference()`.
Author: Martin Braenne Date: 2023-05-04T13:14:04Z New Revision: c849843c3ef73a1cae9040620c4b37e2240f86af URL: https://github.com/llvm/llvm-project/commit/c849843c3ef73a1cae9040620c4b37e2240f86af DIFF: https://github.com/llvm/llvm-project/commit/c849843c3ef73a1cae9040620c4b37e2240f86af.diff LOG: [clang][dataflow][NFC] Eliminate unnecessary helper `stripReference()`. `QualType::getNonReferenceType()` does the same thing. Reviewed By: sammccall Differential Revision: https://reviews.llvm.org/D149744 Added: Modified: clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp index 9745cd8a48311..e306b55753752 100644 --- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp +++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp @@ -276,12 +276,6 @@ BoolValue *getHasValue(Environment &Env, Value *OptionalVal) { return nullptr; } -/// If `Type` is a reference type, returns the type of its pointee. Otherwise, -/// returns `Type` itself. -QualType stripReference(QualType Type) { - return Type->isReferenceType() ? Type->getPointeeType() : Type; -} - /// Returns true if and only if `Type` is an optional type. bool isOptionalType(QualType Type) { if (!Type->isRecordType()) @@ -339,7 +333,7 @@ StorageLocation *maybeInitializeOptionalValueMember(QualType Q, return &ValueLoc; } - auto Ty = stripReference(Q); + auto Ty = Q.getNonReferenceType(); auto *ValueVal = Env.createValue(Ty); if (ValueVal == nullptr) return nullptr; @@ -493,11 +487,13 @@ BoolValue &valueOrConversionHasValue(const FunctionDecl &F, const Expr &E, assert(F.getTemplateSpecializationArgs() != nullptr); assert(F.getTemplateSpecializationArgs()->size() > 0); - const int TemplateParamOptionalWrappersCount = countOptionalWrappers( - *MatchRes.Context, - stripReference(F.getTemplateSpecializationArgs()->get(0).getAsType())); - const int ArgTypeOptionalWrappersCount = - countOptionalWrappers(*MatchRes.Context, stripReference(E.getType())); + const int TemplateParamOptionalWrappersCount = + countOptionalWrappers(*MatchRes.Context, F.getTemplateSpecializationArgs() + ->get(0) + .getAsType() + .getNonReferenceType()); + const int ArgTypeOptionalWrappersCount = countOptionalWrappers( + *MatchRes.Context, E.getType().getNonReferenceType()); // Check if this is a constructor/assignment call for `optional` with // argument of type `U` such that `T` is constructible from `U`. ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] af22be3 - [clang][dataflow] Use a `PointerValue` for `value` property in optional checker.
Author: Martin Braenne Date: 2023-06-05T12:52:51Z New Revision: af22be39038a9c464474410c3a8b3cb428d8b25a URL: https://github.com/llvm/llvm-project/commit/af22be39038a9c464474410c3a8b3cb428d8b25a DIFF: https://github.com/llvm/llvm-project/commit/af22be39038a9c464474410c3a8b3cb428d8b25a.diff LOG: [clang][dataflow] Use a `PointerValue` for `value` property in optional checker. The `ReferenceValue` class will be eliminated as part of the ongoing migration to strict handling of value categories (see https://discourse.llvm.org/t/70086 for details). Reviewed By: gribozavr2 Differential Revision: https://reviews.llvm.org/D152144 Added: Modified: clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp index 7d30473ea5226..1095fd49e8600 100644 --- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp +++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp @@ -307,12 +307,12 @@ StorageLocation *maybeInitializeOptionalValueMember(QualType Q, Environment &Env) { // The "value" property represents a synthetic field. As such, it needs // `StorageLocation`, like normal fields (and other variables). So, we model - // it with a `ReferenceValue`, since that includes a storage location. Once + // it with a `PointerValue`, since that includes a storage location. Once // the property is set, it will be shared by all environments that access the // `Value` representing the optional (here, `OptionalVal`). if (auto *ValueProp = OptionalVal.getProperty("value")) { -auto *ValueRef = clang::cast(ValueProp); -auto &ValueLoc = ValueRef->getReferentLoc(); +auto *ValuePtr = clang::cast(ValueProp); +auto &ValueLoc = ValuePtr->getPointeeLoc(); if (Env.getValue(ValueLoc) == nullptr) { // The property was previously set, but the value has been lost. This can // happen, for example, because of an environment merge (where the two @@ -339,8 +339,8 @@ StorageLocation *maybeInitializeOptionalValueMember(QualType Q, return nullptr; auto &ValueLoc = Env.createStorageLocation(Ty); Env.setValue(ValueLoc, *ValueVal); - auto &ValueRef = Env.create(ValueLoc); - OptionalVal.setProperty("value", ValueRef); + auto &ValuePtr = Env.create(ValueLoc); + OptionalVal.setProperty("value", ValuePtr); return &ValueLoc; } ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] bbeda83 - [clang][dataflow][NFC] Expand comments on losing values in optional checker.
Author: Martin Braenne Date: 2023-06-12T08:46:34Z New Revision: bbeda83090adcb3609f9c1331b2345e7fa547f90 URL: https://github.com/llvm/llvm-project/commit/bbeda83090adcb3609f9c1331b2345e7fa547f90 DIFF: https://github.com/llvm/llvm-project/commit/bbeda83090adcb3609f9c1331b2345e7fa547f90.diff LOG: [clang][dataflow][NFC] Expand comments on losing values in optional checker. While working on the ongoing migration to strict handling of value categories (see https://discourse.llvm.org/t/70086), I ran into issues related to losing the value associated with an optional. This issue is hinted at in the existing comments, but the issue didn't become sufficiently clear to me from those, so I thought it would be worth capturing more details, along with ideas for how this issue might be fixed. Reviewed By: ymandel Differential Revision: https://reviews.llvm.org/D152369 Added: Modified: clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp index 1095fd49e8600..a239d54674e96 100644 --- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp +++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp @@ -315,11 +315,16 @@ StorageLocation *maybeInitializeOptionalValueMember(QualType Q, auto &ValueLoc = ValuePtr->getPointeeLoc(); if (Env.getValue(ValueLoc) == nullptr) { // The property was previously set, but the value has been lost. This can - // happen, for example, because of an environment merge (where the two - // environments mapped the property to diff erent values, which resulted in - // them both being discarded), or when two blocks in the CFG, with neither - // a dominator of the other, visit the same optional value, or even when a - // block is revisited during testing to collect per-statement state. + // happen in various situations, for example: + // - Because of an environment merge (where the two environments mapped + // the property to diff erent values, which resulted in them both being + // discarded). + // - When two blocks in the CFG, with neither a dominator of the other, + // visit the same optional value. (FIXME: This is something we can and + // should fix -- see also the lengthy FIXME below.) + // - Or even when a block is revisited during testing to collect + // per-statement state. + // // FIXME: This situation means that the optional contents are not shared // between branches and the like. Practically, this lack of sharing // reduces the precision of the model when the contents are relevant to @@ -340,6 +345,51 @@ StorageLocation *maybeInitializeOptionalValueMember(QualType Q, auto &ValueLoc = Env.createStorageLocation(Ty); Env.setValue(ValueLoc, *ValueVal); auto &ValuePtr = Env.create(ValueLoc); + // FIXME: + // The change we make to the `value` property below may become visible to + // other blocks that aren't successors of the current block and therefore + // don't see the change we made above mapping `ValueLoc` to `ValueVal`. For + // example: + // + // void target(optional oo, bool b) { + // // `oo` is associated with a `StructValue` here, which we will call + // // `OptionalVal`. + // + // // The `has_value` property is set on `OptionalVal` (but not the + // // `value` property yet). + // if (!oo.has_value()) return; + // + // if (b) { + // // Let's assume we transfer the `if` branch first. + // // + // // This causes us to call `maybeInitializeOptionalValueMember()`, + // // which causes us to set the `value` property on `OptionalVal` + // // (which had not been set until this point). This `value` property + // // refers to a `PointerValue`, which in turn refers to a + // // StorageLocation` that is associated to an `IntegerValue`. + // oo.value(); + // } else { + // // Let's assume we transfer the `else` branch after the `if` branch. + // // + // // We see the `value` property that the `if` branch set on + // // `OptionalVal`, but in the environment for this block, the + // // `StorageLocation` in the `PointerValue` is not associated with any + // // `Value`. + // oo.value(); + // } + // } + // + // This situation is currently "saved" by the code above that checks whether + // the `value` property is already set, and if, the `ValueLoc` is not + // associated with a `ValueVal`, creates a new `ValueVal`. + // + // However, what we should really do is to make sure that the change to the + // `value` property does not "leak" to other blocks that are not succ
[clang] 3f31d32 - [clang][dataflow] Model pointer value for builtin functions.
Author: Martin Braenne Date: 2023-06-12T12:23:18Z New Revision: 3f31d3204bd2726fa8e5c56ea27c8bba0074790e URL: https://github.com/llvm/llvm-project/commit/3f31d3204bd2726fa8e5c56ea27c8bba0074790e DIFF: https://github.com/llvm/llvm-project/commit/3f31d3204bd2726fa8e5c56ea27c8bba0074790e.diff LOG: [clang][dataflow] Model pointer value for builtin functions. This fixes a false positive in the Crubit nullability verification. Reviewed By: gribozavr2 Differential Revision: https://reviews.llvm.org/D152683 Added: Modified: clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Removed: diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp index 8547e5049261f..e0cb872cfa372 100644 --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -400,7 +400,8 @@ class TransferVisitor : public ConstStmtVisitor { Env.setValue(Loc, NullPointerVal); break; } -case CK_FunctionToPointerDecay: { +case CK_FunctionToPointerDecay: +case CK_BuiltinFnToFnPtr: { StorageLocation *PointeeLoc = Env.getStorageLocation(*SubExpr, SkipPast::Reference); if (PointeeLoc == nullptr) diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index 1a2442f0b12db..7077f7344a858 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -5327,4 +5327,37 @@ TEST(TransferTest, FunctionToPointerDecayHasValue) { }); } +// Check that the pointer that a builtin function decays to is associated with +// a value. +TEST(TransferTest, BuiltinFunctionModeled) { + std::string Code = R"( +void target() { + __builtin_expect(0, 0); + // [[p]] +} + )"; + runDataflow( + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) { +using ast_matchers::selectFirst; +using ast_matchers::match; +using ast_matchers::traverse; +using ast_matchers::implicitCastExpr; +using ast_matchers::hasCastKind; + +const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); + +auto *ImplicitCast = selectFirst( +"implicit_cast", +match(traverse(TK_AsIs, + implicitCastExpr(hasCastKind(CK_BuiltinFnToFnPtr)) + .bind("implicit_cast")), + ASTCtx)); + +ASSERT_THAT(ImplicitCast, NotNull()); +EXPECT_THAT(Env.getValueStrict(*ImplicitCast), NotNull()); + }); +} + } // namespace ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits